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