diff options
author | Thierry Escande <thierry.escande@linux.intel.com> | 2013-03-29 06:47:43 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-04-11 10:28:58 -0400 |
commit | 098dafcfb4db0d3c08cffec88c87bbb2f4513f20 (patch) | |
tree | 1f3c5a8d5fae83704919d9b7120301a0aca03cec /net | |
parent | 0b23d666a8857e521384d0eec75a7362b80a39b8 (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.c | 80 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 1 |
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 | ||
32 | static struct list_head llcp_devices; | 32 | static struct list_head llcp_devices; |
33 | 33 | ||
34 | static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb); | ||
35 | |||
34 | void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk) | 36 | void 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 | ||
1352 | static void nfc_llcp_rx_work(struct work_struct *work) | 1354 | static 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); | ||
1393 | next: | ||
1394 | skb_pull(skb, pdu_len); | ||
1395 | } | ||
1396 | } | ||
1397 | |||
1398 | static 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 | |||
1461 | static 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 |