Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012 Intel Corporation. All rights reserved. */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <net/nfc/hci.h> #include "hci.h" /* * Payload is the HCP message data only. Instruction will be prepended. * Guarantees that cb will be called upon completion or timeout delay * counted from the moment the cmd is sent to the transport. */ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, u8 instruction, const u8 *payload, size_t payload_len, data_exchange_cb_t cb, void *cb_context, unsigned long completion_delay) { struct nfc_dev *ndev = hdev->ndev; struct hci_msg *cmd; const u8 *ptr = payload; int hci_len, err; bool firstfrag = true; cmd = kzalloc(sizeof(struct hci_msg), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; INIT_LIST_HEAD(&cmd->msg_l); skb_queue_head_init(&cmd->msg_frags); cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; cmd->cb = cb; cmd->cb_context = cb_context; cmd->completion_delay = completion_delay; hci_len = payload_len + 1; while (hci_len > 0) { struct sk_buff *skb; int skb_len, data_link_len; struct hcp_packet *packet; if (NFC_HCI_HCP_PACKET_HEADER_LEN + hci_len <= hdev->max_data_link_payload) data_link_len = hci_len; else data_link_len = hdev->max_data_link_payload - NFC_HCI_HCP_PACKET_HEADER_LEN; skb_len = ndev->tx_headroom + NFC_HCI_HCP_PACKET_HEADER_LEN + data_link_len + ndev->tx_tailroom; hci_len -= data_link_len; skb = alloc_skb(skb_len, GFP_KERNEL); if (skb == NULL) { err = -ENOMEM; goto out_skb_err; } skb_reserve(skb, ndev->tx_headroom); skb_put(skb, NFC_HCI_HCP_PACKET_HEADER_LEN + data_link_len); /* Only the last fragment will have the cb bit set to 1 */ packet = (struct hcp_packet *)skb->data; packet->header = pipe; if (firstfrag) { firstfrag = false; packet->message.header = HCP_HEADER(type, instruction); } else { packet->message.header = *ptr++; } if (ptr) { memcpy(packet->message.data, ptr, data_link_len - 1); ptr += data_link_len - 1; } /* This is the last fragment, set the cb bit */ if (hci_len == 0) packet->header |= ~NFC_HCI_FRAGMENT; skb_queue_tail(&cmd->msg_frags, skb); } mutex_lock(&hdev->msg_tx_mutex); if (hdev->shutting_down) { err = -ESHUTDOWN; mutex_unlock(&hdev->msg_tx_mutex); goto out_skb_err; } list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); mutex_unlock(&hdev->msg_tx_mutex); schedule_work(&hdev->msg_tx_work); return 0; out_skb_err: skb_queue_purge(&cmd->msg_frags); kfree(cmd); return err; } /* * Receive hcp message for pipe, with type and cmd. * skb contains optional message data only. */ void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, u8 instruction, struct sk_buff *skb) { switch (type) { case NFC_HCI_HCP_RESPONSE: nfc_hci_resp_received(hdev, instruction, skb); break; case NFC_HCI_HCP_COMMAND: nfc_hci_cmd_received(hdev, pipe, instruction, skb); break; case NFC_HCI_HCP_EVENT: nfc_hci_event_received(hdev, pipe, instruction, skb); break; default: pr_err("UNKNOWN MSG Type %d, instruction=%d\n", type, instruction); kfree_skb(skb); break; } } |