summaryrefslogtreecommitdiff
path: root/net/nfc
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2015-10-26 00:54:25 +0300
committerSamuel Ortiz <sameo@linux.intel.com>2015-10-26 08:53:13 +0300
commita1b0b9415817c14d207921582f269d03f848b69f (patch)
tree207337705492431a3750a1ec014d26259ea6c2e5 /net/nfc
parent8a49943f5bc5ff4f835d50451ecf2380eab44d2e (diff)
downloadlinux-a1b0b9415817c14d207921582f269d03f848b69f.tar.xz
NFC: nci: Create pipe on specific gate in nci_hci_connect_gate
Some gates might need to have their pipes explicitly created. Add a call to nci_hci_create_pipe in nci_hci_connect_gate for every gate that is different than NCI_HCI_LINK_MGMT_GATE or NCI_HCI_ADMIN_GATE. In case of an error when opening a pipe, like in hci layer, delete the pipe if it was created. Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/nci/hci.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/net/nfc/nci/hci.c b/net/nfc/nci/hci.c
index af401fff72d9..c96830421097 100644
--- a/net/nfc/nci/hci.c
+++ b/net/nfc/nci/hci.c
@@ -79,6 +79,8 @@ struct nci_hcp_packet {
#define NCI_EVT_HOT_PLUG 0x03
#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01
+#define NCI_HCI_ADM_CREATE_PIPE 0x10
+#define NCI_HCI_ADM_DELETE_PIPE 0x11
/* HCP headers */
#define NCI_HCI_HCP_PACKET_HEADER_LEN 1
@@ -523,6 +525,43 @@ int nci_hci_open_pipe(struct nci_dev *ndev, u8 pipe)
}
EXPORT_SYMBOL(nci_hci_open_pipe);
+static u8 nci_hci_create_pipe(struct nci_dev *ndev, u8 dest_host,
+ u8 dest_gate, int *result)
+{
+ u8 pipe;
+ struct sk_buff *skb;
+ struct nci_hci_create_pipe_params params;
+ struct nci_hci_create_pipe_resp *resp;
+
+ pr_debug("gate=%d\n", dest_gate);
+
+ params.src_gate = NCI_HCI_ADMIN_GATE;
+ params.dest_host = dest_host;
+ params.dest_gate = dest_gate;
+
+ *result = nci_hci_send_cmd(ndev, NCI_HCI_ADMIN_GATE,
+ NCI_HCI_ADM_CREATE_PIPE,
+ (u8 *)&params, sizeof(params), &skb);
+ if (*result < 0)
+ return NCI_HCI_INVALID_PIPE;
+
+ resp = (struct nci_hci_create_pipe_resp *)skb->data;
+ pipe = resp->pipe;
+ kfree_skb(skb);
+
+ pr_debug("pipe created=%d\n", pipe);
+
+ return pipe;
+}
+
+static int nci_hci_delete_pipe(struct nci_dev *ndev, u8 pipe)
+{
+ pr_debug("\n");
+
+ return nci_hci_send_cmd(ndev, NCI_HCI_ADMIN_GATE,
+ NCI_HCI_ADM_DELETE_PIPE, &pipe, 1, NULL);
+}
+
int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
const u8 *param, size_t param_len)
{
@@ -616,6 +655,7 @@ EXPORT_SYMBOL(nci_hci_get_param);
int nci_hci_connect_gate(struct nci_dev *ndev,
u8 dest_host, u8 dest_gate, u8 pipe)
{
+ bool pipe_created = false;
int r;
if (pipe == NCI_HCI_DO_NOT_OPEN_PIPE)
@@ -634,12 +674,26 @@ int nci_hci_connect_gate(struct nci_dev *ndev,
case NCI_HCI_ADMIN_GATE:
pipe = NCI_HCI_ADMIN_PIPE;
break;
+ default:
+ pipe = nci_hci_create_pipe(ndev, dest_host, dest_gate, &r);
+ if (pipe < 0)
+ return r;
+ pipe_created = true;
+ break;
}
open_pipe:
r = nci_hci_open_pipe(ndev, pipe);
- if (r < 0)
+ if (r < 0) {
+ if (pipe_created) {
+ if (nci_hci_delete_pipe(ndev, pipe) < 0) {
+ /* TODO: Cannot clean by deleting pipe...
+ * -> inconsistent state
+ */
+ }
+ }
return r;
+ }
ndev->hci_dev->pipes[pipe].gate = dest_gate;
ndev->hci_dev->pipes[pipe].host = dest_host;