11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28b8d2e08SEric Lapuyade /*
38b8d2e08SEric Lapuyade * Copyright (C) 2012 Intel Corporation. All rights reserved.
48b8d2e08SEric Lapuyade */
58b8d2e08SEric Lapuyade
68b8d2e08SEric Lapuyade #define pr_fmt(fmt) "hci: %s: " fmt, __func__
78b8d2e08SEric Lapuyade
88b8d2e08SEric Lapuyade #include <linux/init.h>
98b8d2e08SEric Lapuyade #include <linux/kernel.h>
108b8d2e08SEric Lapuyade #include <linux/module.h>
118b8d2e08SEric Lapuyade
128b8d2e08SEric Lapuyade #include <net/nfc/hci.h>
138b8d2e08SEric Lapuyade
148b8d2e08SEric Lapuyade #include "hci.h"
158b8d2e08SEric Lapuyade
168b8d2e08SEric Lapuyade /*
178b8d2e08SEric Lapuyade * Payload is the HCP message data only. Instruction will be prepended.
188b8d2e08SEric Lapuyade * Guarantees that cb will be called upon completion or timeout delay
198b8d2e08SEric Lapuyade * counted from the moment the cmd is sent to the transport.
208b8d2e08SEric Lapuyade */
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)218b8d2e08SEric Lapuyade int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
228b8d2e08SEric Lapuyade u8 type, u8 instruction,
238b8d2e08SEric Lapuyade const u8 *payload, size_t payload_len,
24b5faa648SEric Lapuyade data_exchange_cb_t cb, void *cb_context,
258b8d2e08SEric Lapuyade unsigned long completion_delay)
268b8d2e08SEric Lapuyade {
278b8d2e08SEric Lapuyade struct nfc_dev *ndev = hdev->ndev;
288b8d2e08SEric Lapuyade struct hci_msg *cmd;
298b8d2e08SEric Lapuyade const u8 *ptr = payload;
308b8d2e08SEric Lapuyade int hci_len, err;
318b8d2e08SEric Lapuyade bool firstfrag = true;
328b8d2e08SEric Lapuyade
338b8d2e08SEric Lapuyade cmd = kzalloc(sizeof(struct hci_msg), GFP_KERNEL);
348b8d2e08SEric Lapuyade if (cmd == NULL)
358b8d2e08SEric Lapuyade return -ENOMEM;
368b8d2e08SEric Lapuyade
378b8d2e08SEric Lapuyade INIT_LIST_HEAD(&cmd->msg_l);
388b8d2e08SEric Lapuyade skb_queue_head_init(&cmd->msg_frags);
398b8d2e08SEric Lapuyade cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false;
408b8d2e08SEric Lapuyade cmd->cb = cb;
41b5faa648SEric Lapuyade cmd->cb_context = cb_context;
428b8d2e08SEric Lapuyade cmd->completion_delay = completion_delay;
438b8d2e08SEric Lapuyade
448b8d2e08SEric Lapuyade hci_len = payload_len + 1;
458b8d2e08SEric Lapuyade while (hci_len > 0) {
468b8d2e08SEric Lapuyade struct sk_buff *skb;
478b8d2e08SEric Lapuyade int skb_len, data_link_len;
488b8d2e08SEric Lapuyade struct hcp_packet *packet;
498b8d2e08SEric Lapuyade
508b8d2e08SEric Lapuyade if (NFC_HCI_HCP_PACKET_HEADER_LEN + hci_len <=
518b8d2e08SEric Lapuyade hdev->max_data_link_payload)
528b8d2e08SEric Lapuyade data_link_len = hci_len;
538b8d2e08SEric Lapuyade else
548b8d2e08SEric Lapuyade data_link_len = hdev->max_data_link_payload -
558b8d2e08SEric Lapuyade NFC_HCI_HCP_PACKET_HEADER_LEN;
568b8d2e08SEric Lapuyade
578b8d2e08SEric Lapuyade skb_len = ndev->tx_headroom + NFC_HCI_HCP_PACKET_HEADER_LEN +
588b8d2e08SEric Lapuyade data_link_len + ndev->tx_tailroom;
598b8d2e08SEric Lapuyade hci_len -= data_link_len;
608b8d2e08SEric Lapuyade
618b8d2e08SEric Lapuyade skb = alloc_skb(skb_len, GFP_KERNEL);
628b8d2e08SEric Lapuyade if (skb == NULL) {
638b8d2e08SEric Lapuyade err = -ENOMEM;
648b8d2e08SEric Lapuyade goto out_skb_err;
658b8d2e08SEric Lapuyade }
668b8d2e08SEric Lapuyade skb_reserve(skb, ndev->tx_headroom);
678b8d2e08SEric Lapuyade
688b8d2e08SEric Lapuyade skb_put(skb, NFC_HCI_HCP_PACKET_HEADER_LEN + data_link_len);
698b8d2e08SEric Lapuyade
708b8d2e08SEric Lapuyade /* Only the last fragment will have the cb bit set to 1 */
718b8d2e08SEric Lapuyade packet = (struct hcp_packet *)skb->data;
728b8d2e08SEric Lapuyade packet->header = pipe;
738b8d2e08SEric Lapuyade if (firstfrag) {
748b8d2e08SEric Lapuyade firstfrag = false;
758b8d2e08SEric Lapuyade packet->message.header = HCP_HEADER(type, instruction);
768b8d2e08SEric Lapuyade } else {
77*de4feb4eSKees Cook packet->message.header = *ptr++;
78*de4feb4eSKees Cook }
79*de4feb4eSKees Cook if (ptr) {
80*de4feb4eSKees Cook memcpy(packet->message.data, ptr, data_link_len - 1);
81*de4feb4eSKees Cook ptr += data_link_len - 1;
828b8d2e08SEric Lapuyade }
838b8d2e08SEric Lapuyade
848b8d2e08SEric Lapuyade /* This is the last fragment, set the cb bit */
858b8d2e08SEric Lapuyade if (hci_len == 0)
868b8d2e08SEric Lapuyade packet->header |= ~NFC_HCI_FRAGMENT;
878b8d2e08SEric Lapuyade
888b8d2e08SEric Lapuyade skb_queue_tail(&cmd->msg_frags, skb);
898b8d2e08SEric Lapuyade }
908b8d2e08SEric Lapuyade
918b8d2e08SEric Lapuyade mutex_lock(&hdev->msg_tx_mutex);
92f0c91038SEric Lapuyade
93f0c91038SEric Lapuyade if (hdev->shutting_down) {
94f0c91038SEric Lapuyade err = -ESHUTDOWN;
95f0c91038SEric Lapuyade mutex_unlock(&hdev->msg_tx_mutex);
96f0c91038SEric Lapuyade goto out_skb_err;
97f0c91038SEric Lapuyade }
98f0c91038SEric Lapuyade
99f8bf65bfSMathias Jeppsson list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
1008b8d2e08SEric Lapuyade mutex_unlock(&hdev->msg_tx_mutex);
1018b8d2e08SEric Lapuyade
102916082b0SLinus Torvalds schedule_work(&hdev->msg_tx_work);
1038b8d2e08SEric Lapuyade
1048b8d2e08SEric Lapuyade return 0;
1058b8d2e08SEric Lapuyade
1068b8d2e08SEric Lapuyade out_skb_err:
1078b8d2e08SEric Lapuyade skb_queue_purge(&cmd->msg_frags);
1088b8d2e08SEric Lapuyade kfree(cmd);
1098b8d2e08SEric Lapuyade
1108b8d2e08SEric Lapuyade return err;
1118b8d2e08SEric Lapuyade }
1128b8d2e08SEric Lapuyade
1138b8d2e08SEric Lapuyade /*
1148b8d2e08SEric Lapuyade * Receive hcp message for pipe, with type and cmd.
1158b8d2e08SEric Lapuyade * skb contains optional message data only.
1168b8d2e08SEric Lapuyade */
nfc_hci_hcp_message_rx(struct nfc_hci_dev * hdev,u8 pipe,u8 type,u8 instruction,struct sk_buff * skb)1178b8d2e08SEric Lapuyade void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type,
1188b8d2e08SEric Lapuyade u8 instruction, struct sk_buff *skb)
1198b8d2e08SEric Lapuyade {
1208b8d2e08SEric Lapuyade switch (type) {
1218b8d2e08SEric Lapuyade case NFC_HCI_HCP_RESPONSE:
1228b8d2e08SEric Lapuyade nfc_hci_resp_received(hdev, instruction, skb);
1238b8d2e08SEric Lapuyade break;
1248b8d2e08SEric Lapuyade case NFC_HCI_HCP_COMMAND:
1258b8d2e08SEric Lapuyade nfc_hci_cmd_received(hdev, pipe, instruction, skb);
1268b8d2e08SEric Lapuyade break;
1278b8d2e08SEric Lapuyade case NFC_HCI_HCP_EVENT:
1288b8d2e08SEric Lapuyade nfc_hci_event_received(hdev, pipe, instruction, skb);
1298b8d2e08SEric Lapuyade break;
1308b8d2e08SEric Lapuyade default:
1318b8d2e08SEric Lapuyade pr_err("UNKNOWN MSG Type %d, instruction=%d\n",
1328b8d2e08SEric Lapuyade type, instruction);
1338b8d2e08SEric Lapuyade kfree_skb(skb);
1348b8d2e08SEric Lapuyade break;
1358b8d2e08SEric Lapuyade }
1368b8d2e08SEric Lapuyade }
137