cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hci.c (19618B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  The NFC Controller Interface is the communication protocol between an
      4 *  NFC Controller (NFCC) and a Device Host (DH).
      5 *  This is the HCI over NCI implementation, as specified in the 10.2
      6 *  section of the NCI 1.1 specification.
      7 *
      8 *  Copyright (C) 2014  STMicroelectronics SAS. All rights reserved.
      9 */
     10
     11#include <linux/skbuff.h>
     12
     13#include "../nfc.h"
     14#include <net/nfc/nci.h>
     15#include <net/nfc/nci_core.h>
     16#include <linux/nfc.h>
     17
     18struct nci_data {
     19	u8 conn_id;
     20	u8 pipe;
     21	u8 cmd;
     22	const u8 *data;
     23	u32 data_len;
     24} __packed;
     25
     26struct nci_hci_create_pipe_params {
     27	u8 src_gate;
     28	u8 dest_host;
     29	u8 dest_gate;
     30} __packed;
     31
     32struct nci_hci_create_pipe_resp {
     33	u8 src_host;
     34	u8 src_gate;
     35	u8 dest_host;
     36	u8 dest_gate;
     37	u8 pipe;
     38} __packed;
     39
     40struct nci_hci_delete_pipe_noti {
     41	u8 pipe;
     42} __packed;
     43
     44struct nci_hci_all_pipe_cleared_noti {
     45	u8 host;
     46} __packed;
     47
     48struct nci_hcp_message {
     49	u8 header;      /* type -cmd,evt,rsp- + instruction */
     50	u8 data[];
     51} __packed;
     52
     53struct nci_hcp_packet {
     54	u8 header;      /* cbit+pipe */
     55	struct nci_hcp_message message;
     56} __packed;
     57
     58#define NCI_HCI_ANY_SET_PARAMETER  0x01
     59#define NCI_HCI_ANY_GET_PARAMETER  0x02
     60#define NCI_HCI_ANY_CLOSE_PIPE     0x04
     61#define NCI_HCI_ADM_CLEAR_ALL_PIPE 0x14
     62
     63#define NCI_HFP_NO_CHAINING        0x80
     64
     65#define NCI_NFCEE_ID_HCI                0x80
     66
     67#define NCI_EVT_HOT_PLUG           0x03
     68
     69#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY       0x01
     70#define NCI_HCI_ADM_CREATE_PIPE			0x10
     71#define NCI_HCI_ADM_DELETE_PIPE			0x11
     72
     73/* HCP headers */
     74#define NCI_HCI_HCP_PACKET_HEADER_LEN      1
     75#define NCI_HCI_HCP_MESSAGE_HEADER_LEN     1
     76#define NCI_HCI_HCP_HEADER_LEN             2
     77
     78/* HCP types */
     79#define NCI_HCI_HCP_COMMAND        0x00
     80#define NCI_HCI_HCP_EVENT          0x01
     81#define NCI_HCI_HCP_RESPONSE       0x02
     82
     83#define NCI_HCI_ADM_NOTIFY_PIPE_CREATED     0x12
     84#define NCI_HCI_ADM_NOTIFY_PIPE_DELETED     0x13
     85#define NCI_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED 0x15
     86
     87#define NCI_HCI_FRAGMENT           0x7f
     88#define NCI_HCP_HEADER(type, instr) ((((type) & 0x03) << 6) |\
     89				      ((instr) & 0x3f))
     90
     91#define NCI_HCP_MSG_GET_TYPE(header) ((header & 0xc0) >> 6)
     92#define NCI_HCP_MSG_GET_CMD(header)  (header & 0x3f)
     93#define NCI_HCP_MSG_GET_PIPE(header) (header & 0x7f)
     94
     95static int nci_hci_result_to_errno(u8 result)
     96{
     97	switch (result) {
     98	case NCI_HCI_ANY_OK:
     99		return 0;
    100	case NCI_HCI_ANY_E_REG_PAR_UNKNOWN:
    101		return -EOPNOTSUPP;
    102	case NCI_HCI_ANY_E_TIMEOUT:
    103		return -ETIME;
    104	default:
    105		return -1;
    106	}
    107}
    108
    109/* HCI core */
    110static void nci_hci_reset_pipes(struct nci_hci_dev *hdev)
    111{
    112	int i;
    113
    114	for (i = 0; i < NCI_HCI_MAX_PIPES; i++) {
    115		hdev->pipes[i].gate = NCI_HCI_INVALID_GATE;
    116		hdev->pipes[i].host = NCI_HCI_INVALID_HOST;
    117	}
    118	memset(hdev->gate2pipe, NCI_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
    119}
    120
    121static void nci_hci_reset_pipes_per_host(struct nci_dev *ndev, u8 host)
    122{
    123	int i;
    124
    125	for (i = 0; i < NCI_HCI_MAX_PIPES; i++) {
    126		if (ndev->hci_dev->pipes[i].host == host) {
    127			ndev->hci_dev->pipes[i].gate = NCI_HCI_INVALID_GATE;
    128			ndev->hci_dev->pipes[i].host = NCI_HCI_INVALID_HOST;
    129		}
    130	}
    131}
    132
    133/* Fragment HCI data over NCI packet.
    134 * NFC Forum NCI 10.2.2 Data Exchange:
    135 * The payload of the Data Packets sent on the Logical Connection SHALL be
    136 * valid HCP packets, as defined within [ETSI_102622]. Each Data Packet SHALL
    137 * contain a single HCP packet. NCI Segmentation and Reassembly SHALL NOT be
    138 * applied to Data Messages in either direction. The HCI fragmentation mechanism
    139 * is used if required.
    140 */
    141static int nci_hci_send_data(struct nci_dev *ndev, u8 pipe,
    142			     const u8 data_type, const u8 *data,
    143			     size_t data_len)
    144{
    145	const struct nci_conn_info *conn_info;
    146	struct sk_buff *skb;
    147	int len, i, r;
    148	u8 cb = pipe;
    149
    150	conn_info = ndev->hci_dev->conn_info;
    151	if (!conn_info)
    152		return -EPROTO;
    153
    154	i = 0;
    155	skb = nci_skb_alloc(ndev, conn_info->max_pkt_payload_len +
    156			    NCI_DATA_HDR_SIZE, GFP_ATOMIC);
    157	if (!skb)
    158		return -ENOMEM;
    159
    160	skb_reserve(skb, NCI_DATA_HDR_SIZE + 2);
    161	*(u8 *)skb_push(skb, 1) = data_type;
    162
    163	do {
    164		/* If last packet add NCI_HFP_NO_CHAINING */
    165		if (i + conn_info->max_pkt_payload_len -
    166		    (skb->len + 1) >= data_len) {
    167			cb |= NCI_HFP_NO_CHAINING;
    168			len = data_len - i;
    169		} else {
    170			len = conn_info->max_pkt_payload_len - skb->len - 1;
    171		}
    172
    173		*(u8 *)skb_push(skb, 1) = cb;
    174
    175		if (len > 0)
    176			skb_put_data(skb, data + i, len);
    177
    178		r = nci_send_data(ndev, conn_info->conn_id, skb);
    179		if (r < 0)
    180			return r;
    181
    182		i += len;
    183
    184		if (i < data_len) {
    185			skb = nci_skb_alloc(ndev,
    186					    conn_info->max_pkt_payload_len +
    187					    NCI_DATA_HDR_SIZE, GFP_ATOMIC);
    188			if (!skb)
    189				return -ENOMEM;
    190
    191			skb_reserve(skb, NCI_DATA_HDR_SIZE + 1);
    192		}
    193	} while (i < data_len);
    194
    195	return i;
    196}
    197
    198static void nci_hci_send_data_req(struct nci_dev *ndev, const void *opt)
    199{
    200	const struct nci_data *data = opt;
    201
    202	nci_hci_send_data(ndev, data->pipe, data->cmd,
    203			  data->data, data->data_len);
    204}
    205
    206int nci_hci_send_event(struct nci_dev *ndev, u8 gate, u8 event,
    207		       const u8 *param, size_t param_len)
    208{
    209	u8 pipe = ndev->hci_dev->gate2pipe[gate];
    210
    211	if (pipe == NCI_HCI_INVALID_PIPE)
    212		return -EADDRNOTAVAIL;
    213
    214	return nci_hci_send_data(ndev, pipe,
    215			NCI_HCP_HEADER(NCI_HCI_HCP_EVENT, event),
    216			param, param_len);
    217}
    218EXPORT_SYMBOL(nci_hci_send_event);
    219
    220int nci_hci_send_cmd(struct nci_dev *ndev, u8 gate, u8 cmd,
    221		     const u8 *param, size_t param_len,
    222		     struct sk_buff **skb)
    223{
    224	const struct nci_hcp_message *message;
    225	const struct nci_conn_info *conn_info;
    226	struct nci_data data;
    227	int r;
    228	u8 pipe = ndev->hci_dev->gate2pipe[gate];
    229
    230	if (pipe == NCI_HCI_INVALID_PIPE)
    231		return -EADDRNOTAVAIL;
    232
    233	conn_info = ndev->hci_dev->conn_info;
    234	if (!conn_info)
    235		return -EPROTO;
    236
    237	data.conn_id = conn_info->conn_id;
    238	data.pipe = pipe;
    239	data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND, cmd);
    240	data.data = param;
    241	data.data_len = param_len;
    242
    243	r = nci_request(ndev, nci_hci_send_data_req, &data,
    244			msecs_to_jiffies(NCI_DATA_TIMEOUT));
    245	if (r == NCI_STATUS_OK) {
    246		message = (struct nci_hcp_message *)conn_info->rx_skb->data;
    247		r = nci_hci_result_to_errno(
    248			NCI_HCP_MSG_GET_CMD(message->header));
    249		skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
    250
    251		if (!r && skb)
    252			*skb = conn_info->rx_skb;
    253	}
    254
    255	return r;
    256}
    257EXPORT_SYMBOL(nci_hci_send_cmd);
    258
    259int nci_hci_clear_all_pipes(struct nci_dev *ndev)
    260{
    261	int r;
    262
    263	r = nci_hci_send_cmd(ndev, NCI_HCI_ADMIN_GATE,
    264			     NCI_HCI_ADM_CLEAR_ALL_PIPE, NULL, 0, NULL);
    265	if (r < 0)
    266		return r;
    267
    268	nci_hci_reset_pipes(ndev->hci_dev);
    269	return r;
    270}
    271EXPORT_SYMBOL(nci_hci_clear_all_pipes);
    272
    273static void nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
    274				   u8 event, struct sk_buff *skb)
    275{
    276	if (ndev->ops->hci_event_received)
    277		ndev->ops->hci_event_received(ndev, pipe, event, skb);
    278}
    279
    280static void nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe,
    281				 u8 cmd, struct sk_buff *skb)
    282{
    283	u8 gate = ndev->hci_dev->pipes[pipe].gate;
    284	u8 status = NCI_HCI_ANY_OK | ~NCI_HCI_FRAGMENT;
    285	u8 dest_gate, new_pipe;
    286	struct nci_hci_create_pipe_resp *create_info;
    287	struct nci_hci_delete_pipe_noti *delete_info;
    288	struct nci_hci_all_pipe_cleared_noti *cleared_info;
    289
    290	pr_debug("from gate %x pipe %x cmd %x\n", gate, pipe, cmd);
    291
    292	switch (cmd) {
    293	case NCI_HCI_ADM_NOTIFY_PIPE_CREATED:
    294		if (skb->len != 5) {
    295			status = NCI_HCI_ANY_E_NOK;
    296			goto exit;
    297		}
    298		create_info = (struct nci_hci_create_pipe_resp *)skb->data;
    299		dest_gate = create_info->dest_gate;
    300		new_pipe = create_info->pipe;
    301		if (new_pipe >= NCI_HCI_MAX_PIPES) {
    302			status = NCI_HCI_ANY_E_NOK;
    303			goto exit;
    304		}
    305
    306		/* Save the new created pipe and bind with local gate,
    307		 * the description for skb->data[3] is destination gate id
    308		 * but since we received this cmd from host controller, we
    309		 * are the destination and it is our local gate
    310		 */
    311		ndev->hci_dev->gate2pipe[dest_gate] = new_pipe;
    312		ndev->hci_dev->pipes[new_pipe].gate = dest_gate;
    313		ndev->hci_dev->pipes[new_pipe].host =
    314						create_info->src_host;
    315		break;
    316	case NCI_HCI_ANY_OPEN_PIPE:
    317		/* If the pipe is not created report an error */
    318		if (gate == NCI_HCI_INVALID_GATE) {
    319			status = NCI_HCI_ANY_E_NOK;
    320			goto exit;
    321		}
    322		break;
    323	case NCI_HCI_ADM_NOTIFY_PIPE_DELETED:
    324		if (skb->len != 1) {
    325			status = NCI_HCI_ANY_E_NOK;
    326			goto exit;
    327		}
    328		delete_info = (struct nci_hci_delete_pipe_noti *)skb->data;
    329		if (delete_info->pipe >= NCI_HCI_MAX_PIPES) {
    330			status = NCI_HCI_ANY_E_NOK;
    331			goto exit;
    332		}
    333
    334		ndev->hci_dev->pipes[delete_info->pipe].gate =
    335						NCI_HCI_INVALID_GATE;
    336		ndev->hci_dev->pipes[delete_info->pipe].host =
    337						NCI_HCI_INVALID_HOST;
    338		break;
    339	case NCI_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED:
    340		if (skb->len != 1) {
    341			status = NCI_HCI_ANY_E_NOK;
    342			goto exit;
    343		}
    344
    345		cleared_info =
    346			(struct nci_hci_all_pipe_cleared_noti *)skb->data;
    347		nci_hci_reset_pipes_per_host(ndev, cleared_info->host);
    348		break;
    349	default:
    350		pr_debug("Discarded unknown cmd %x to gate %x\n", cmd, gate);
    351		break;
    352	}
    353
    354	if (ndev->ops->hci_cmd_received)
    355		ndev->ops->hci_cmd_received(ndev, pipe, cmd, skb);
    356
    357exit:
    358	nci_hci_send_data(ndev, pipe, status, NULL, 0);
    359
    360	kfree_skb(skb);
    361}
    362
    363static void nci_hci_resp_received(struct nci_dev *ndev, u8 pipe,
    364				  struct sk_buff *skb)
    365{
    366	struct nci_conn_info *conn_info;
    367
    368	conn_info = ndev->hci_dev->conn_info;
    369	if (!conn_info)
    370		goto exit;
    371
    372	conn_info->rx_skb = skb;
    373
    374exit:
    375	nci_req_complete(ndev, NCI_STATUS_OK);
    376}
    377
    378/* Receive hcp message for pipe, with type and cmd.
    379 * skb contains optional message data only.
    380 */
    381static void nci_hci_hcp_message_rx(struct nci_dev *ndev, u8 pipe,
    382				   u8 type, u8 instruction, struct sk_buff *skb)
    383{
    384	switch (type) {
    385	case NCI_HCI_HCP_RESPONSE:
    386		nci_hci_resp_received(ndev, pipe, skb);
    387		break;
    388	case NCI_HCI_HCP_COMMAND:
    389		nci_hci_cmd_received(ndev, pipe, instruction, skb);
    390		break;
    391	case NCI_HCI_HCP_EVENT:
    392		nci_hci_event_received(ndev, pipe, instruction, skb);
    393		break;
    394	default:
    395		pr_err("UNKNOWN MSG Type %d, instruction=%d\n",
    396		       type, instruction);
    397		kfree_skb(skb);
    398		break;
    399	}
    400
    401	nci_req_complete(ndev, NCI_STATUS_OK);
    402}
    403
    404static void nci_hci_msg_rx_work(struct work_struct *work)
    405{
    406	struct nci_hci_dev *hdev =
    407		container_of(work, struct nci_hci_dev, msg_rx_work);
    408	struct sk_buff *skb;
    409	const struct nci_hcp_message *message;
    410	u8 pipe, type, instruction;
    411
    412	while ((skb = skb_dequeue(&hdev->msg_rx_queue)) != NULL) {
    413		pipe = NCI_HCP_MSG_GET_PIPE(skb->data[0]);
    414		skb_pull(skb, NCI_HCI_HCP_PACKET_HEADER_LEN);
    415		message = (struct nci_hcp_message *)skb->data;
    416		type = NCI_HCP_MSG_GET_TYPE(message->header);
    417		instruction = NCI_HCP_MSG_GET_CMD(message->header);
    418		skb_pull(skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
    419
    420		nci_hci_hcp_message_rx(hdev->ndev, pipe,
    421				       type, instruction, skb);
    422	}
    423}
    424
    425void nci_hci_data_received_cb(void *context,
    426			      struct sk_buff *skb, int err)
    427{
    428	struct nci_dev *ndev = (struct nci_dev *)context;
    429	struct nci_hcp_packet *packet;
    430	u8 pipe, type;
    431	struct sk_buff *hcp_skb;
    432	struct sk_buff *frag_skb;
    433	int msg_len;
    434
    435	if (err) {
    436		nci_req_complete(ndev, err);
    437		return;
    438	}
    439
    440	packet = (struct nci_hcp_packet *)skb->data;
    441	if ((packet->header & ~NCI_HCI_FRAGMENT) == 0) {
    442		skb_queue_tail(&ndev->hci_dev->rx_hcp_frags, skb);
    443		return;
    444	}
    445
    446	/* it's the last fragment. Does it need re-aggregation? */
    447	if (skb_queue_len(&ndev->hci_dev->rx_hcp_frags)) {
    448		pipe = NCI_HCP_MSG_GET_PIPE(packet->header);
    449		skb_queue_tail(&ndev->hci_dev->rx_hcp_frags, skb);
    450
    451		msg_len = 0;
    452		skb_queue_walk(&ndev->hci_dev->rx_hcp_frags, frag_skb) {
    453			msg_len += (frag_skb->len -
    454				    NCI_HCI_HCP_PACKET_HEADER_LEN);
    455		}
    456
    457		hcp_skb = nfc_alloc_recv_skb(NCI_HCI_HCP_PACKET_HEADER_LEN +
    458					     msg_len, GFP_KERNEL);
    459		if (!hcp_skb) {
    460			nci_req_complete(ndev, -ENOMEM);
    461			return;
    462		}
    463
    464		skb_put_u8(hcp_skb, pipe);
    465
    466		skb_queue_walk(&ndev->hci_dev->rx_hcp_frags, frag_skb) {
    467			msg_len = frag_skb->len - NCI_HCI_HCP_PACKET_HEADER_LEN;
    468			skb_put_data(hcp_skb,
    469				     frag_skb->data + NCI_HCI_HCP_PACKET_HEADER_LEN,
    470				     msg_len);
    471		}
    472
    473		skb_queue_purge(&ndev->hci_dev->rx_hcp_frags);
    474	} else {
    475		packet->header &= NCI_HCI_FRAGMENT;
    476		hcp_skb = skb;
    477	}
    478
    479	/* if this is a response, dispatch immediately to
    480	 * unblock waiting cmd context. Otherwise, enqueue to dispatch
    481	 * in separate context where handler can also execute command.
    482	 */
    483	packet = (struct nci_hcp_packet *)hcp_skb->data;
    484	type = NCI_HCP_MSG_GET_TYPE(packet->message.header);
    485	if (type == NCI_HCI_HCP_RESPONSE) {
    486		pipe = NCI_HCP_MSG_GET_PIPE(packet->header);
    487		skb_pull(hcp_skb, NCI_HCI_HCP_PACKET_HEADER_LEN);
    488		nci_hci_hcp_message_rx(ndev, pipe, type,
    489				       NCI_STATUS_OK, hcp_skb);
    490	} else {
    491		skb_queue_tail(&ndev->hci_dev->msg_rx_queue, hcp_skb);
    492		schedule_work(&ndev->hci_dev->msg_rx_work);
    493	}
    494}
    495
    496int nci_hci_open_pipe(struct nci_dev *ndev, u8 pipe)
    497{
    498	struct nci_data data;
    499	const struct nci_conn_info *conn_info;
    500
    501	conn_info = ndev->hci_dev->conn_info;
    502	if (!conn_info)
    503		return -EPROTO;
    504
    505	data.conn_id = conn_info->conn_id;
    506	data.pipe = pipe;
    507	data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND,
    508				       NCI_HCI_ANY_OPEN_PIPE);
    509	data.data = NULL;
    510	data.data_len = 0;
    511
    512	return nci_request(ndev, nci_hci_send_data_req, &data,
    513			   msecs_to_jiffies(NCI_DATA_TIMEOUT));
    514}
    515EXPORT_SYMBOL(nci_hci_open_pipe);
    516
    517static u8 nci_hci_create_pipe(struct nci_dev *ndev, u8 dest_host,
    518			      u8 dest_gate, int *result)
    519{
    520	u8 pipe;
    521	struct sk_buff *skb;
    522	struct nci_hci_create_pipe_params params;
    523	const struct nci_hci_create_pipe_resp *resp;
    524
    525	pr_debug("gate=%d\n", dest_gate);
    526
    527	params.src_gate = NCI_HCI_ADMIN_GATE;
    528	params.dest_host = dest_host;
    529	params.dest_gate = dest_gate;
    530
    531	*result = nci_hci_send_cmd(ndev, NCI_HCI_ADMIN_GATE,
    532				   NCI_HCI_ADM_CREATE_PIPE,
    533				   (u8 *)&params, sizeof(params), &skb);
    534	if (*result < 0)
    535		return NCI_HCI_INVALID_PIPE;
    536
    537	resp = (struct nci_hci_create_pipe_resp *)skb->data;
    538	pipe = resp->pipe;
    539	kfree_skb(skb);
    540
    541	pr_debug("pipe created=%d\n", pipe);
    542
    543	return pipe;
    544}
    545
    546static int nci_hci_delete_pipe(struct nci_dev *ndev, u8 pipe)
    547{
    548	return nci_hci_send_cmd(ndev, NCI_HCI_ADMIN_GATE,
    549				NCI_HCI_ADM_DELETE_PIPE, &pipe, 1, NULL);
    550}
    551
    552int nci_hci_set_param(struct nci_dev *ndev, u8 gate, u8 idx,
    553		      const u8 *param, size_t param_len)
    554{
    555	const struct nci_hcp_message *message;
    556	const struct nci_conn_info *conn_info;
    557	struct nci_data data;
    558	int r;
    559	u8 *tmp;
    560	u8 pipe = ndev->hci_dev->gate2pipe[gate];
    561
    562	pr_debug("idx=%d to gate %d\n", idx, gate);
    563
    564	if (pipe == NCI_HCI_INVALID_PIPE)
    565		return -EADDRNOTAVAIL;
    566
    567	conn_info = ndev->hci_dev->conn_info;
    568	if (!conn_info)
    569		return -EPROTO;
    570
    571	tmp = kmalloc(1 + param_len, GFP_KERNEL);
    572	if (!tmp)
    573		return -ENOMEM;
    574
    575	*tmp = idx;
    576	memcpy(tmp + 1, param, param_len);
    577
    578	data.conn_id = conn_info->conn_id;
    579	data.pipe = pipe;
    580	data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND,
    581				       NCI_HCI_ANY_SET_PARAMETER);
    582	data.data = tmp;
    583	data.data_len = param_len + 1;
    584
    585	r = nci_request(ndev, nci_hci_send_data_req, &data,
    586			msecs_to_jiffies(NCI_DATA_TIMEOUT));
    587	if (r == NCI_STATUS_OK) {
    588		message = (struct nci_hcp_message *)conn_info->rx_skb->data;
    589		r = nci_hci_result_to_errno(
    590			NCI_HCP_MSG_GET_CMD(message->header));
    591		skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
    592	}
    593
    594	kfree(tmp);
    595	return r;
    596}
    597EXPORT_SYMBOL(nci_hci_set_param);
    598
    599int nci_hci_get_param(struct nci_dev *ndev, u8 gate, u8 idx,
    600		      struct sk_buff **skb)
    601{
    602	const struct nci_hcp_message *message;
    603	const struct nci_conn_info *conn_info;
    604	struct nci_data data;
    605	int r;
    606	u8 pipe = ndev->hci_dev->gate2pipe[gate];
    607
    608	pr_debug("idx=%d to gate %d\n", idx, gate);
    609
    610	if (pipe == NCI_HCI_INVALID_PIPE)
    611		return -EADDRNOTAVAIL;
    612
    613	conn_info = ndev->hci_dev->conn_info;
    614	if (!conn_info)
    615		return -EPROTO;
    616
    617	data.conn_id = conn_info->conn_id;
    618	data.pipe = pipe;
    619	data.cmd = NCI_HCP_HEADER(NCI_HCI_HCP_COMMAND,
    620				  NCI_HCI_ANY_GET_PARAMETER);
    621	data.data = &idx;
    622	data.data_len = 1;
    623
    624	r = nci_request(ndev, nci_hci_send_data_req, &data,
    625			msecs_to_jiffies(NCI_DATA_TIMEOUT));
    626
    627	if (r == NCI_STATUS_OK) {
    628		message = (struct nci_hcp_message *)conn_info->rx_skb->data;
    629		r = nci_hci_result_to_errno(
    630			NCI_HCP_MSG_GET_CMD(message->header));
    631		skb_pull(conn_info->rx_skb, NCI_HCI_HCP_MESSAGE_HEADER_LEN);
    632
    633		if (!r && skb)
    634			*skb = conn_info->rx_skb;
    635	}
    636
    637	return r;
    638}
    639EXPORT_SYMBOL(nci_hci_get_param);
    640
    641int nci_hci_connect_gate(struct nci_dev *ndev,
    642			 u8 dest_host, u8 dest_gate, u8 pipe)
    643{
    644	bool pipe_created = false;
    645	int r;
    646
    647	if (pipe == NCI_HCI_DO_NOT_OPEN_PIPE)
    648		return 0;
    649
    650	if (ndev->hci_dev->gate2pipe[dest_gate] != NCI_HCI_INVALID_PIPE)
    651		return -EADDRINUSE;
    652
    653	if (pipe != NCI_HCI_INVALID_PIPE)
    654		goto open_pipe;
    655
    656	switch (dest_gate) {
    657	case NCI_HCI_LINK_MGMT_GATE:
    658		pipe = NCI_HCI_LINK_MGMT_PIPE;
    659	break;
    660	case NCI_HCI_ADMIN_GATE:
    661		pipe = NCI_HCI_ADMIN_PIPE;
    662	break;
    663	default:
    664		pipe = nci_hci_create_pipe(ndev, dest_host, dest_gate, &r);
    665		if (pipe == NCI_HCI_INVALID_PIPE)
    666			return r;
    667		pipe_created = true;
    668		break;
    669	}
    670
    671open_pipe:
    672	r = nci_hci_open_pipe(ndev, pipe);
    673	if (r < 0) {
    674		if (pipe_created) {
    675			if (nci_hci_delete_pipe(ndev, pipe) < 0) {
    676				/* TODO: Cannot clean by deleting pipe...
    677				 * -> inconsistent state
    678				 */
    679			}
    680		}
    681		return r;
    682	}
    683
    684	ndev->hci_dev->pipes[pipe].gate = dest_gate;
    685	ndev->hci_dev->pipes[pipe].host = dest_host;
    686	ndev->hci_dev->gate2pipe[dest_gate] = pipe;
    687
    688	return 0;
    689}
    690EXPORT_SYMBOL(nci_hci_connect_gate);
    691
    692static int nci_hci_dev_connect_gates(struct nci_dev *ndev,
    693				     u8 gate_count,
    694				     const struct nci_hci_gate *gates)
    695{
    696	int r;
    697
    698	while (gate_count--) {
    699		r = nci_hci_connect_gate(ndev, gates->dest_host,
    700					 gates->gate, gates->pipe);
    701		if (r < 0)
    702			return r;
    703		gates++;
    704	}
    705
    706	return 0;
    707}
    708
    709int nci_hci_dev_session_init(struct nci_dev *ndev)
    710{
    711	struct nci_conn_info *conn_info;
    712	struct sk_buff *skb;
    713	int r;
    714
    715	ndev->hci_dev->count_pipes = 0;
    716	ndev->hci_dev->expected_pipes = 0;
    717
    718	conn_info = ndev->hci_dev->conn_info;
    719	if (!conn_info)
    720		return -EPROTO;
    721
    722	conn_info->data_exchange_cb = nci_hci_data_received_cb;
    723	conn_info->data_exchange_cb_context = ndev;
    724
    725	nci_hci_reset_pipes(ndev->hci_dev);
    726
    727	if (ndev->hci_dev->init_data.gates[0].gate != NCI_HCI_ADMIN_GATE)
    728		return -EPROTO;
    729
    730	r = nci_hci_connect_gate(ndev,
    731				 ndev->hci_dev->init_data.gates[0].dest_host,
    732				 ndev->hci_dev->init_data.gates[0].gate,
    733				 ndev->hci_dev->init_data.gates[0].pipe);
    734	if (r < 0)
    735		return r;
    736
    737	r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
    738			      NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY, &skb);
    739	if (r < 0)
    740		return r;
    741
    742	if (skb->len &&
    743	    skb->len == strlen(ndev->hci_dev->init_data.session_id) &&
    744	    !memcmp(ndev->hci_dev->init_data.session_id, skb->data, skb->len) &&
    745	    ndev->ops->hci_load_session) {
    746		/* Restore gate<->pipe table from some proprietary location. */
    747		r = ndev->ops->hci_load_session(ndev);
    748	} else {
    749		r = nci_hci_clear_all_pipes(ndev);
    750		if (r < 0)
    751			goto exit;
    752
    753		r = nci_hci_dev_connect_gates(ndev,
    754					      ndev->hci_dev->init_data.gate_count,
    755					      ndev->hci_dev->init_data.gates);
    756		if (r < 0)
    757			goto exit;
    758
    759		r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
    760				      NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY,
    761				      ndev->hci_dev->init_data.session_id,
    762				      strlen(ndev->hci_dev->init_data.session_id));
    763	}
    764
    765exit:
    766	kfree_skb(skb);
    767
    768	return r;
    769}
    770EXPORT_SYMBOL(nci_hci_dev_session_init);
    771
    772struct nci_hci_dev *nci_hci_allocate(struct nci_dev *ndev)
    773{
    774	struct nci_hci_dev *hdev;
    775
    776	hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
    777	if (!hdev)
    778		return NULL;
    779
    780	skb_queue_head_init(&hdev->rx_hcp_frags);
    781	INIT_WORK(&hdev->msg_rx_work, nci_hci_msg_rx_work);
    782	skb_queue_head_init(&hdev->msg_rx_queue);
    783	hdev->ndev = ndev;
    784
    785	return hdev;
    786}
    787
    788void nci_hci_deallocate(struct nci_dev *ndev)
    789{
    790	kfree(ndev->hci_dev);
    791}