diff --git a/net/nfc/nci/hci.c b/net/nfc/nci/hci.c
index c03e8a0bd..bdfe9eee6 100644
--- a/net/nfc/nci/hci.c
+++ b/net/nfc/nci/hci.c
@@ -107,6 +107,38 @@ static int nci_hci_result_to_errno(u8 result)
}
}
+/* Take the HCP response stored by nci_hci_resp_received().
+ *
+ * The response skb is detached from conn_info so that it is consumed
+ * exactly once. A request can also be completed without a response
+ * being stored (an HCP command or event received while the request is
+ * pending, or an unrelated NCI response), so a missing response is an
+ * error rather than a reason to reuse whatever skb was stored last.
+ */
+static int nci_hci_take_resp(struct nci_conn_info *conn_info,
+ struct sk_buff **skb)
+{
+ const struct nci_hcp_message *message;
+ struct sk_buff *rx_skb;
+ int r;
+
+ rx_skb = conn_info->rx_skb;
+ conn_info->rx_skb = NULL;
+ if (!rx_skb)
+ return -EPROTO;
+
+ message = (struct nci_hcp_message *)rx_skb->data;
+ r = nci_hci_result_to_errno(NCI_HCP_MSG_GET_CMD(message->header));
+ skb_pull(rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
+
+ if (!r && skb)
+ *skb = rx_skb;
+ else
+ kfree_skb(rx_skb);
+
+ return r;
+}
+
/* HCI core */
static void nci_hci_reset_pipes(struct nci_hci_dev *hdev)
{@@ -222,8 +254,7 @@ int nci_hci_send_cmd(struct nci_dev *ndev, u8 gate, u8 cmd,
const u8 *param, size_t param_len,
struct sk_buff **skb)
{
- const struct nci_hcp_message *message;
- const struct nci_conn_info *conn_info;
+ struct nci_conn_info *conn_info;
struct nci_data data;
int r;
u8 pipe = ndev->hci_dev->gate2pipe[gate];@@ -243,15 +274,8 @@ int nci_hci_send_cmd(struct nci_dev *ndev, u8 gate, u8 cmd,
r = nci_request(ndev, nci_hci_send_data_req, &data,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
- if (r == NCI_STATUS_OK) {
- message = (struct nci_hcp_message *)conn_info->rx_skb->data;
- r = nci_hci_result_to_errno(
- NCI_HCP_MSG_GET_CMD(message->header));
- skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
-
- if (!r && skb)
- *skb = conn_info->rx_skb;
- }
+ if (r == NCI_STATUS_OK)
+ r = nci_hci_take_resp(conn_info, skb);
return r;
}@@ -508,7 +532,8 @@ void nci_hci_data_received_cb(void *context,
int nci_hci_open_pipe(struct nci_dev *ndev, u8 pipe)
{
struct nci_data data;
- const struct nci_conn_info *conn_info;
+ struct nci_conn_info *conn_info;
+ int r;
conn_info = ndev->hci_dev->conn_info;
if (!conn_info)@@ -521,8 +546,12 @@ int nci_hci_open_pipe(struct nci_dev *ndev, u8 pipe)
data.data = NULL;
data.data_len = 0;
- return nci_request(ndev, nci_hci_send_data_req, &data,
- msecs_to_jiffies(NCI_DATA_TIMEOUT));
+ r = nci_request(ndev, nci_hci_send_data_req, &data,
+ msecs_to_jiffies(NCI_DATA_TIMEOUT));
+ if (r == NCI_STATUS_OK)
+ r = nci_hci_take_resp(conn_info, NULL);
+
+ return r;
}
EXPORT_SYMBOL(nci_hci_open_pipe);
@@ -566,8 +595,7 @@ static int nci_hci_delete_pipe(struct nci_dev *ndev, u8 pipe)
int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
const u8 *param, size_t param_len)
{
- const struct nci_hcp_message *message;
- const struct nci_conn_info *conn_info;
+ struct nci_conn_info *conn_info;
struct nci_data data;
int r;
u8 *tmp;@@ -598,12 +626,8 @@ int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
r = nci_request(ndev, nci_hci_send_data_req, &data,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
- if (r == NCI_STATUS_OK) {
- message = (struct nci_hcp_message *)conn_info->rx_skb->data;
- r = nci_hci_result_to_errno(
- NCI_HCP_MSG_GET_CMD(message->header));
- skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
- }
+ if (r == NCI_STATUS_OK)
+ r = nci_hci_take_resp(conn_info, NULL);
kfree(tmp);
return r;@@ -613,8 +637,7 @@ EXPORT_SYMBOL(nci_hci_set_param);
int nci_hci_get_param(struct nci_dev *ndev, u8 gate, u8 idx,
struct sk_buff **skb)
{
- const struct nci_hcp_message *message;
- const struct nci_conn_info *conn_info;
+ struct nci_conn_info *conn_info;
struct nci_data data;
int r;
u8 pipe = ndev->hci_dev->gate2pipe[gate];@@ -637,16 +660,8 @@ int nci_hci_get_param(struct nci_dev *ndev, u8 gate, u8 idx,
r = nci_request(ndev, nci_hci_send_data_req, &data,
msecs_to_jiffies(NCI_DATA_TIMEOUT));
-
- if (r == NCI_STATUS_OK) {
- message = (struct nci_hcp_message *)conn_info->rx_skb->data;
- r = nci_hci_result_to_errno(
- NCI_HCP_MSG_GET_CMD(message->header));
- skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
-
- if (!r && skb)
- *skb = conn_info->rx_skb;
- }
+ if (r == NCI_STATUS_OK)
+ r = nci_hci_take_resp(conn_info, skb);
return r;
}--
2.43.0