ntf.c 15.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
 *  The NFC Controller Interface is the communication protocol between an
 *  NFC Controller (NFCC) and a Device Host (DH).
 *
 *  Copyright (C) 2011 Texas Instruments, Inc.
 *
 *  Written by Ilan Elias <ilane@ti.com>
 *
 *  Acknowledgements:
 *  This file is based on hci_event.c, which was written
 *  by Maxim Krasnyansky.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

28
#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
Joe Perches's avatar
Joe Perches committed
29

30
31
32
33
34
35
36
37
38
39
40
41
42
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/skbuff.h>

#include "../nfc.h"
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
#include <linux/nfc.h>

/* Handle NCI Notification packets */

static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
43
					     struct sk_buff *skb)
44
45
46
47
{
	struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
	int i;

48
	pr_debug("num_entries %d\n", ntf->num_entries);
49
50
51
52
53
54

	if (ntf->num_entries > NCI_MAX_NUM_CONN)
		ntf->num_entries = NCI_MAX_NUM_CONN;

	/* update the credits */
	for (i = 0; i < ntf->num_entries; i++) {
55
56
57
		ntf->conn_entries[i].conn_id =
			nci_conn_id(&ntf->conn_entries[i].conn_id);

Joe Perches's avatar
Joe Perches committed
58
59
60
		pr_debug("entry[%d]: conn_id %d, credits %d\n",
			 i, ntf->conn_entries[i].conn_id,
			 ntf->conn_entries[i].credits);
61

62
		if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
63
64
			/* found static rf connection */
			atomic_add(ntf->conn_entries[i].credits,
Samuel Ortiz's avatar
Samuel Ortiz committed
65
				   &ndev->credits_cnt);
66
67
68
69
70
71
72
73
		}
	}

	/* trigger the next tx */
	if (!skb_queue_empty(&ndev->tx_q))
		queue_work(ndev->tx_wq, &ndev->tx_work);
}

74
static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
75
					      struct sk_buff *skb)
76
77
78
79
80
81
82
{
	__u8 status = skb->data[0];

	pr_debug("status 0x%x\n", status);

	if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
		/* Activation failed, so complete the request
Samuel Ortiz's avatar
Samuel Ortiz committed
83
		   (the state remains the same) */
84
85
86
87
		nci_req_complete(ndev, status);
	}
}

88
89
90
91
92
93
94
95
96
97
98
99
100
101
static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
						struct sk_buff *skb)
{
	struct nci_core_intf_error_ntf *ntf = (void *) skb->data;

	ntf->conn_id = nci_conn_id(&ntf->conn_id);

	pr_debug("status 0x%x, conn_id %d\n", ntf->status, ntf->conn_id);

	/* complete the data exchange transaction, if exists */
	if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
		nci_data_exchange_complete(ndev, NULL, -EIO);
}

102
static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
103
			struct rf_tech_specific_params_nfca_poll *nfca_poll,
Samuel Ortiz's avatar
Samuel Ortiz committed
104
						     __u8 *data)
105
106
107
108
109
110
{
	nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
	data += 2;

	nfca_poll->nfcid1_len = *data++;

Joe Perches's avatar
Joe Perches committed
111
112
	pr_debug("sens_res 0x%x, nfcid1_len %d\n",
		 nfca_poll->sens_res, nfca_poll->nfcid1_len);
113
114
115
116
117
118
119
120
121

	memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
	data += nfca_poll->nfcid1_len;

	nfca_poll->sel_res_len = *data++;

	if (nfca_poll->sel_res_len != 0)
		nfca_poll->sel_res = *data++;

Joe Perches's avatar
Joe Perches committed
122
123
124
	pr_debug("sel_res_len %d, sel_res 0x%x\n",
		 nfca_poll->sel_res_len,
		 nfca_poll->sel_res);
125
126
127
128

	return data;
}

129
static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
130
			struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
Samuel Ortiz's avatar
Samuel Ortiz committed
131
						     __u8 *data)
132
133
134
135
136
137
138
139
140
141
142
143
{
	nfcb_poll->sensb_res_len = *data++;

	pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);

	memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len);
	data += nfcb_poll->sensb_res_len;

	return data;
}

static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
144
			struct rf_tech_specific_params_nfcf_poll *nfcf_poll,
Samuel Ortiz's avatar
Samuel Ortiz committed
145
						     __u8 *data)
146
147
148
149
150
{
	nfcf_poll->bit_rate = *data++;
	nfcf_poll->sensf_res_len = *data++;

	pr_debug("bit_rate %d, sensf_res_len %d\n",
Samuel Ortiz's avatar
Samuel Ortiz committed
151
		 nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
152
153
154
155
156
157
158

	memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len);
	data += nfcf_poll->sensf_res_len;

	return data;
}

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
static int nci_add_new_protocol(struct nci_dev *ndev,
				struct nfc_target *target,
				__u8 rf_protocol,
				__u8 rf_tech_and_mode,
				void *params)
{
	struct rf_tech_specific_params_nfca_poll *nfca_poll;
	struct rf_tech_specific_params_nfcb_poll *nfcb_poll;
	struct rf_tech_specific_params_nfcf_poll *nfcf_poll;
	__u32 protocol;

	if (rf_protocol == NCI_RF_PROTOCOL_T2T)
		protocol = NFC_PROTO_MIFARE_MASK;
	else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)
		protocol = NFC_PROTO_ISO14443_MASK;
	else if (rf_protocol == NCI_RF_PROTOCOL_T3T)
		protocol = NFC_PROTO_FELICA_MASK;
	else
		protocol = 0;

	if (!(protocol & ndev->poll_prots)) {
		pr_err("the target found does not have the desired protocol\n");
		return -EPROTO;
	}

	if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) {
		nfca_poll = (struct rf_tech_specific_params_nfca_poll *)params;

		target->sens_res = nfca_poll->sens_res;
		target->sel_res = nfca_poll->sel_res;
		target->nfcid1_len = nfca_poll->nfcid1_len;
		if (target->nfcid1_len > 0) {
			memcpy(target->nfcid1, nfca_poll->nfcid1,
Samuel Ortiz's avatar
Samuel Ortiz committed
192
			       target->nfcid1_len);
193
194
195
196
197
198
199
		}
	} else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) {
		nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params;

		target->sensb_res_len = nfcb_poll->sensb_res_len;
		if (target->sensb_res_len > 0) {
			memcpy(target->sensb_res, nfcb_poll->sensb_res,
Samuel Ortiz's avatar
Samuel Ortiz committed
200
			       target->sensb_res_len);
201
202
203
204
205
206
207
		}
	} else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) {
		nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params;

		target->sensf_res_len = nfcf_poll->sensf_res_len;
		if (target->sensf_res_len > 0) {
			memcpy(target->sensf_res, nfcf_poll->sensf_res,
Samuel Ortiz's avatar
Samuel Ortiz committed
208
			       target->sensf_res_len);
209
210
211
212
213
214
215
216
217
218
219
220
221
222
		}
	} else {
		pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode);
		return -EPROTO;
	}

	target->supported_protocols |= protocol;

	pr_debug("protocol 0x%x\n", protocol);

	return 0;
}

static void nci_add_new_target(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
223
			       struct nci_rf_discover_ntf *ntf)
224
225
226
227
228
229
{
	struct nfc_target *target;
	int i, rc;

	for (i = 0; i < ndev->n_targets; i++) {
		target = &ndev->targets[i];
230
		if (target->logical_idx == ntf->rf_discovery_id) {
231
232
			/* This target already exists, add the new protocol */
			nci_add_new_protocol(ndev, target, ntf->rf_protocol,
Samuel Ortiz's avatar
Samuel Ortiz committed
233
234
					     ntf->rf_tech_and_mode,
					     &ntf->rf_tech_specific_params);
235
236
237
238
239
240
241
242
243
244
245
246
247
			return;
		}
	}

	/* This is a new target, check if we've enough room */
	if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) {
		pr_debug("not enough room, ignoring new target...\n");
		return;
	}

	target = &ndev->targets[ndev->n_targets];

	rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
Samuel Ortiz's avatar
Samuel Ortiz committed
248
249
				  ntf->rf_tech_and_mode,
				  &ntf->rf_tech_specific_params);
250
	if (!rc) {
251
		target->logical_idx = ntf->rf_discovery_id;
252
253
		ndev->n_targets++;

254
		pr_debug("logical idx %d, n_targets %d\n", target->logical_idx,
Samuel Ortiz's avatar
Samuel Ortiz committed
255
			 ndev->n_targets);
256
257
258
259
260
261
	}
}

void nci_clear_target_list(struct nci_dev *ndev)
{
	memset(ndev->targets, 0,
Samuel Ortiz's avatar
Samuel Ortiz committed
262
	       (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS));
263
264
265
266
267

	ndev->n_targets = 0;
}

static void nci_rf_discover_ntf_packet(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
268
				       struct sk_buff *skb)
269
270
271
272
273
274
275
276
277
278
279
280
281
282
{
	struct nci_rf_discover_ntf ntf;
	__u8 *data = skb->data;
	bool add_target = true;

	ntf.rf_discovery_id = *data++;
	ntf.rf_protocol = *data++;
	ntf.rf_tech_and_mode = *data++;
	ntf.rf_tech_specific_params_len = *data++;

	pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id);
	pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol);
	pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode);
	pr_debug("rf_tech_specific_params_len %d\n",
Samuel Ortiz's avatar
Samuel Ortiz committed
283
		 ntf.rf_tech_specific_params_len);
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

	if (ntf.rf_tech_specific_params_len > 0) {
		switch (ntf.rf_tech_and_mode) {
		case NCI_NFC_A_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfca_passive_poll(ndev,
				&(ntf.rf_tech_specific_params.nfca_poll), data);
			break;

		case NCI_NFC_B_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfcb_passive_poll(ndev,
				&(ntf.rf_tech_specific_params.nfcb_poll), data);
			break;

		case NCI_NFC_F_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfcf_passive_poll(ndev,
				&(ntf.rf_tech_specific_params.nfcf_poll), data);
			break;

		default:
			pr_err("unsupported rf_tech_and_mode 0x%x\n",
			       ntf.rf_tech_and_mode);
			data += ntf.rf_tech_specific_params_len;
			add_target = false;
		}
	}

	ntf.ntf_type = *data++;
	pr_debug("ntf_type %d\n", ntf.ntf_type);

	if (add_target == true)
		nci_add_new_target(ndev, &ntf);

	if (ntf.ntf_type == NCI_DISCOVER_NTF_TYPE_MORE) {
		atomic_set(&ndev->state, NCI_W4_ALL_DISCOVERIES);
	} else {
		atomic_set(&ndev->state, NCI_W4_HOST_SELECT);
		nfc_targets_found(ndev->nfc_dev, ndev->targets,
Samuel Ortiz's avatar
Samuel Ortiz committed
321
				  ndev->n_targets);
322
323
324
	}
}

325
326
327
328
static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
			struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
{
	struct activation_params_nfca_poll_iso_dep *nfca_poll;
329
	struct activation_params_nfcb_poll_iso_dep *nfcb_poll;
330
331
332
333
334

	switch (ntf->activation_rf_tech_and_mode) {
	case NCI_NFC_A_PASSIVE_POLL_MODE:
		nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
		nfca_poll->rats_res_len = *data++;
335
		pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
336
337
		if (nfca_poll->rats_res_len > 0) {
			memcpy(nfca_poll->rats_res,
Samuel Ortiz's avatar
Samuel Ortiz committed
338
			       data, nfca_poll->rats_res_len);
339
340
341
		}
		break;

342
343
344
	case NCI_NFC_B_PASSIVE_POLL_MODE:
		nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
		nfcb_poll->attrib_res_len = *data++;
Samuel Ortiz's avatar
Samuel Ortiz committed
345
		pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
346
347
		if (nfcb_poll->attrib_res_len > 0) {
			memcpy(nfcb_poll->attrib_res,
Samuel Ortiz's avatar
Samuel Ortiz committed
348
			       data, nfcb_poll->attrib_res_len);
349
350
351
		}
		break;

352
	default:
Joe Perches's avatar
Joe Perches committed
353
354
		pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
		       ntf->activation_rf_tech_and_mode);
355
		return NCI_STATUS_RF_PROTOCOL_ERROR;
356
357
	}

358
	return NCI_STATUS_OK;
359
360
}

361
static void nci_target_auto_activated(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
362
				      struct nci_rf_intf_activated_ntf *ntf)
363
{
364
365
	struct nfc_target *target;
	int rc;
366

367
	target = &ndev->targets[ndev->n_targets];
368

369
	rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
Samuel Ortiz's avatar
Samuel Ortiz committed
370
371
				  ntf->activation_rf_tech_and_mode,
				  &ntf->rf_tech_specific_params);
372
	if (rc)
373
374
		return;

375
	target->logical_idx = ntf->rf_discovery_id;
376
	ndev->n_targets++;
377

378
379
	pr_debug("logical idx %d, n_targets %d\n",
		 target->logical_idx, ndev->n_targets);
380

381
	nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets);
382
383
}

384
static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
385
					     struct sk_buff *skb)
386
{
387
	struct nci_rf_intf_activated_ntf ntf;
388
	__u8 *data = skb->data;
389
	int err = NCI_STATUS_OK;
390

391
	ntf.rf_discovery_id = *data++;
392
	ntf.rf_interface = *data++;
393
	ntf.rf_protocol = *data++;
394
	ntf.activation_rf_tech_and_mode = *data++;
395
396
	ntf.max_data_pkt_payload_size = *data++;
	ntf.initial_num_credits = *data++;
397
398
	ntf.rf_tech_specific_params_len = *data++;

Joe Perches's avatar
Joe Perches committed
399
	pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id);
400
	pr_debug("rf_interface 0x%x\n", ntf.rf_interface);
Joe Perches's avatar
Joe Perches committed
401
402
403
	pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol);
	pr_debug("activation_rf_tech_and_mode 0x%x\n",
		 ntf.activation_rf_tech_and_mode);
404
405
	pr_debug("max_data_pkt_payload_size 0x%x\n",
		 ntf.max_data_pkt_payload_size);
Samuel Ortiz's avatar
Samuel Ortiz committed
406
407
	pr_debug("initial_num_credits 0x%x\n",
		 ntf.initial_num_credits);
Joe Perches's avatar
Joe Perches committed
408
409
	pr_debug("rf_tech_specific_params_len %d\n",
		 ntf.rf_tech_specific_params_len);
410

411
412
413
414
	if (ntf.rf_tech_specific_params_len > 0) {
		switch (ntf.activation_rf_tech_and_mode) {
		case NCI_NFC_A_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfca_passive_poll(ndev,
415
				&(ntf.rf_tech_specific_params.nfca_poll), data);
416
417
			break;

418
419
		case NCI_NFC_B_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfcb_passive_poll(ndev,
420
				&(ntf.rf_tech_specific_params.nfcb_poll), data);
421
422
423
424
			break;

		case NCI_NFC_F_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfcf_passive_poll(ndev,
425
				&(ntf.rf_tech_specific_params.nfcf_poll), data);
426
427
			break;

428
		default:
Joe Perches's avatar
Joe Perches committed
429
430
			pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
			       ntf.activation_rf_tech_and_mode);
431
432
			err = NCI_STATUS_RF_PROTOCOL_ERROR;
			goto exit;
433
434
		}
	}
435

436
437
438
439
440
	ntf.data_exch_rf_tech_and_mode = *data++;
	ntf.data_exch_tx_bit_rate = *data++;
	ntf.data_exch_rx_bit_rate = *data++;
	ntf.activation_params_len = *data++;

Joe Perches's avatar
Joe Perches committed
441
442
	pr_debug("data_exch_rf_tech_and_mode 0x%x\n",
		 ntf.data_exch_rf_tech_and_mode);
Samuel Ortiz's avatar
Samuel Ortiz committed
443
444
445
	pr_debug("data_exch_tx_bit_rate 0x%x\n", ntf.data_exch_tx_bit_rate);
	pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate);
	pr_debug("activation_params_len %d\n", ntf.activation_params_len);
446
447

	if (ntf.activation_params_len > 0) {
448
		switch (ntf.rf_interface) {
449
450
		case NCI_RF_INTERFACE_ISO_DEP:
			err = nci_extract_activation_params_iso_dep(ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
451
								    &ntf, data);
452
453
454
455
456
457
458
			break;

		case NCI_RF_INTERFACE_FRAME:
			/* no activation params */
			break;

		default:
459
460
			pr_err("unsupported rf_interface 0x%x\n",
			       ntf.rf_interface);
461
462
			err = NCI_STATUS_RF_PROTOCOL_ERROR;
			break;
463
		}
464
465
	}

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
exit:
	if (err == NCI_STATUS_OK) {
		ndev->max_data_pkt_payload_size = ntf.max_data_pkt_payload_size;
		ndev->initial_num_credits = ntf.initial_num_credits;

		/* set the available credits to initial value */
		atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
	}

	if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
		/* A single target was found and activated automatically */
		atomic_set(&ndev->state, NCI_POLL_ACTIVE);
		if (err == NCI_STATUS_OK)
			nci_target_auto_activated(ndev, &ntf);
	} else {	/* ndev->state == NCI_W4_HOST_SELECT */
		/* A selected target was activated, so complete the request */
		atomic_set(&ndev->state, NCI_POLL_ACTIVE);
		nci_req_complete(ndev, err);
	}
485
486
487
}

static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
Samuel Ortiz's avatar
Samuel Ortiz committed
488
					 struct sk_buff *skb)
489
{
490
	struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
491

Joe Perches's avatar
Joe Perches committed
492
	pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason);
493
494
495
496
497
498
499

	/* drop tx data queue */
	skb_queue_purge(&ndev->tx_q);

	/* drop partial rx data packet */
	if (ndev->rx_data_reassembly) {
		kfree_skb(ndev->rx_data_reassembly);
500
		ndev->rx_data_reassembly = NULL;
501
502
503
	}

	/* complete the data exchange transaction, if exists */
504
	if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
505
		nci_data_exchange_complete(ndev, NULL, -EIO);
506

507
508
	nci_clear_target_list(ndev);
	atomic_set(&ndev->state, NCI_IDLE);
509
	nci_req_complete(ndev, NCI_STATUS_OK);
510
511
512
513
514
515
}

void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
{
	__u16 ntf_opcode = nci_opcode(skb->data);

Joe Perches's avatar
Joe Perches committed
516
517
518
519
520
	pr_debug("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
		 nci_pbf(skb->data),
		 nci_opcode_gid(ntf_opcode),
		 nci_opcode_oid(ntf_opcode),
		 nci_plen(skb->data));
521
522
523
524
525
526
527
528
529

	/* strip the nci control header */
	skb_pull(skb, NCI_CTRL_HDR_SIZE);

	switch (ntf_opcode) {
	case NCI_OP_CORE_CONN_CREDITS_NTF:
		nci_core_conn_credits_ntf_packet(ndev, skb);
		break;

530
531
532
533
	case NCI_OP_CORE_GENERIC_ERROR_NTF:
		nci_core_generic_error_ntf_packet(ndev, skb);
		break;

534
535
536
537
	case NCI_OP_CORE_INTF_ERROR_NTF:
		nci_core_conn_intf_error_ntf_packet(ndev, skb);
		break;

538
539
540
541
	case NCI_OP_RF_DISCOVER_NTF:
		nci_rf_discover_ntf_packet(ndev, skb);
		break;

542
543
	case NCI_OP_RF_INTF_ACTIVATED_NTF:
		nci_rf_intf_activated_ntf_packet(ndev, skb);
544
545
546
547
548
549
550
		break;

	case NCI_OP_RF_DEACTIVATE_NTF:
		nci_rf_deactivate_ntf_packet(ndev, skb);
		break;

	default:
Joe Perches's avatar
Joe Perches committed
551
		pr_err("unknown ntf opcode 0x%x\n", ntf_opcode);
552
553
554
555
556
		break;
	}

	kfree_skb(skb);
}