aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@linux.intel.com>2013-03-29 06:47:43 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-04-11 10:28:58 -0400
commit098dafcfb4db0d3c08cffec88c87bbb2f4513f20 (patch)
tree1f3c5a8d5fae83704919d9b7120301a0aca03cec /net
parent0b23d666a8857e521384d0eec75a7362b80a39b8 (diff)
NFC: llcp: Aggregated frames support
This adds support for AGF PDUs. For each PDU contained in the AGF, a new sk_buff is allocated and dispatched to its corresponding handler. Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/nfc/llcp/llcp.c80
-rw-r--r--net/nfc/llcp/llcp.h1
2 files changed, 69 insertions, 12 deletions
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 7de0368aff0c..79de8bafd426 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
31 31
32static struct list_head llcp_devices; 32static struct list_head llcp_devices;
33 33
34static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
35
34void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk) 36void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
35{ 37{
36 write_lock(&l->lock); 38 write_lock(&l->lock);
@@ -1349,19 +1351,54 @@ exit:
1349 nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); 1351 nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
1350} 1352}
1351 1353
1352static void nfc_llcp_rx_work(struct work_struct *work) 1354static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb)
1353{ 1355{
1354 struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, 1356 u8 ptype;
1355 rx_work); 1357 u16 pdu_len;
1356 u8 dsap, ssap, ptype; 1358 struct sk_buff *new_skb;
1357 struct sk_buff *skb;
1358 1359
1359 skb = local->rx_pending; 1360 if (skb->len <= LLCP_HEADER_SIZE) {
1360 if (skb == NULL) { 1361 pr_err("Malformed AGF PDU\n");
1361 pr_debug("No pending SKB\n");
1362 return; 1362 return;
1363 } 1363 }
1364 1364
1365 skb_pull(skb, LLCP_HEADER_SIZE);
1366
1367 while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) {
1368 pdu_len = skb->data[0] << 8 | skb->data[1];
1369
1370 skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE);
1371
1372 if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) {
1373 pr_err("Malformed AGF PDU\n");
1374 return;
1375 }
1376
1377 ptype = nfc_llcp_ptype(skb);
1378
1379 if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF)
1380 goto next;
1381
1382 new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL);
1383 if (new_skb == NULL) {
1384 pr_err("Could not allocate PDU\n");
1385 return;
1386 }
1387
1388 memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len);
1389
1390 nfc_llcp_rx_skb(local, new_skb);
1391
1392 kfree_skb(new_skb);
1393next:
1394 skb_pull(skb, pdu_len);
1395 }
1396}
1397
1398static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb)
1399{
1400 u8 dsap, ssap, ptype;
1401
1365 ptype = nfc_llcp_ptype(skb); 1402 ptype = nfc_llcp_ptype(skb);
1366 dsap = nfc_llcp_dsap(skb); 1403 dsap = nfc_llcp_dsap(skb);
1367 ssap = nfc_llcp_ssap(skb); 1404 ssap = nfc_llcp_ssap(skb);
@@ -1372,10 +1409,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
1372 print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, 1409 print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
1373 16, 1, skb->data, skb->len, true); 1410 16, 1, skb->data, skb->len, true);
1374 1411
1375 __net_timestamp(skb);
1376
1377 nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
1378
1379 switch (ptype) { 1412 switch (ptype) {
1380 case LLCP_PDU_SYMM: 1413 case LLCP_PDU_SYMM:
1381 pr_debug("SYMM\n"); 1414 pr_debug("SYMM\n");
@@ -1418,7 +1451,30 @@ static void nfc_llcp_rx_work(struct work_struct *work)
1418 nfc_llcp_recv_hdlc(local, skb); 1451 nfc_llcp_recv_hdlc(local, skb);
1419 break; 1452 break;
1420 1453
1454 case LLCP_PDU_AGF:
1455 pr_debug("AGF frame\n");
1456 nfc_llcp_recv_agf(local, skb);
1457 break;
1421 } 1458 }
1459}
1460
1461static void nfc_llcp_rx_work(struct work_struct *work)
1462{
1463 struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
1464 rx_work);
1465 struct sk_buff *skb;
1466
1467 skb = local->rx_pending;
1468 if (skb == NULL) {
1469 pr_debug("No pending SKB\n");
1470 return;
1471 }
1472
1473 __net_timestamp(skb);
1474
1475 nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
1476
1477 nfc_llcp_rx_skb(local, skb);
1422 1478
1423 schedule_work(&local->tx_work); 1479 schedule_work(&local->tx_work);
1424 kfree_skb(local->rx_pending); 1480 kfree_skb(local->rx_pending);
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index 53054d337bf9..6dfde1ed648f 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -162,6 +162,7 @@ struct nfc_llcp_ui_cb {
162 162
163#define LLCP_HEADER_SIZE 2 163#define LLCP_HEADER_SIZE 2
164#define LLCP_SEQUENCE_SIZE 1 164#define LLCP_SEQUENCE_SIZE 1
165#define LLCP_AGF_PDU_HEADER_SIZE 2
165 166
166/* LLCP versions: 1.1 is 1.0 plus SDP */ 167/* LLCP versions: 1.1 is 1.0 plus SDP */
167#define LLCP_VERSION_10 0x10 168#define LLCP_VERSION_10 0x10