diff options
author | Hiren Tandel <hirent@marvell.com> | 2014-05-05 06:43:31 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-05-19 18:06:04 -0400 |
commit | 57be1f3f3ec1ccab6432615ca161c4c9ece2a2aa (patch) | |
tree | bb0021acf67dcb66957f0482cb89f894d8fa77f0 /net/nfc | |
parent | c79d9f9ef86683824c195b093106222ff0611c10 (diff) |
NFC: Add RAW socket type support for SOCKPROTO_RAW
This allows for a more generic NFC sniffing by using SOCKPROTO_RAW
SOCK_RAW to read RAW NFC frames. This is for sniffing anything but LLCP
(HCI, NCI, etc...).
Signed-off-by: Hiren Tandel <hirent@marvell.com>
Signed-off-by: Rahul Tank <rahult@marvell.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/llcp_commands.c | 2 | ||||
-rw-r--r-- | net/nfc/llcp_core.c | 11 | ||||
-rw-r--r-- | net/nfc/nfc.h | 6 | ||||
-rw-r--r-- | net/nfc/rawsock.c | 94 |
4 files changed, 102 insertions, 11 deletions
diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index bec6ed15f503..a3ad69a4c648 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c | |||
@@ -387,7 +387,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) | |||
387 | 387 | ||
388 | __net_timestamp(skb); | 388 | __net_timestamp(skb); |
389 | 389 | ||
390 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX); | 390 | nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_TX); |
391 | 391 | ||
392 | return nfc_data_exchange(dev, local->target_idx, skb, | 392 | return nfc_data_exchange(dev, local->target_idx, skb, |
393 | nfc_llcp_recv, local); | 393 | nfc_llcp_recv, local); |
diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index b4671958fcf9..f6278da68763 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c | |||
@@ -680,16 +680,17 @@ void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | |||
680 | continue; | 680 | continue; |
681 | 681 | ||
682 | if (skb_copy == NULL) { | 682 | if (skb_copy == NULL) { |
683 | skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE, | 683 | skb_copy = __pskb_copy(skb, NFC_RAW_HEADER_SIZE, |
684 | GFP_ATOMIC); | 684 | GFP_ATOMIC); |
685 | 685 | ||
686 | if (skb_copy == NULL) | 686 | if (skb_copy == NULL) |
687 | continue; | 687 | continue; |
688 | 688 | ||
689 | data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE); | 689 | data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE); |
690 | 690 | ||
691 | data[0] = local->dev ? local->dev->idx : 0xFF; | 691 | data[0] = local->dev ? local->dev->idx : 0xFF; |
692 | data[1] = direction; | 692 | data[1] = direction & 0x01; |
693 | data[1] |= (RAW_PAYLOAD_LLCP << 1); | ||
693 | } | 694 | } |
694 | 695 | ||
695 | nskb = skb_clone(skb_copy, GFP_ATOMIC); | 696 | nskb = skb_clone(skb_copy, GFP_ATOMIC); |
@@ -747,7 +748,7 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
747 | __net_timestamp(skb); | 748 | __net_timestamp(skb); |
748 | 749 | ||
749 | nfc_llcp_send_to_raw_sock(local, skb, | 750 | nfc_llcp_send_to_raw_sock(local, skb, |
750 | NFC_LLCP_DIRECTION_TX); | 751 | NFC_DIRECTION_TX); |
751 | 752 | ||
752 | ret = nfc_data_exchange(local->dev, local->target_idx, | 753 | ret = nfc_data_exchange(local->dev, local->target_idx, |
753 | skb, nfc_llcp_recv, local); | 754 | skb, nfc_llcp_recv, local); |
@@ -1476,7 +1477,7 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1476 | 1477 | ||
1477 | __net_timestamp(skb); | 1478 | __net_timestamp(skb); |
1478 | 1479 | ||
1479 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | 1480 | nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_RX); |
1480 | 1481 | ||
1481 | nfc_llcp_rx_skb(local, skb); | 1482 | nfc_llcp_rx_skb(local, skb); |
1482 | 1483 | ||
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 9d6e74f7e6b3..88d60064890e 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h | |||
@@ -40,6 +40,12 @@ struct nfc_rawsock { | |||
40 | struct work_struct tx_work; | 40 | struct work_struct tx_work; |
41 | bool tx_work_scheduled; | 41 | bool tx_work_scheduled; |
42 | }; | 42 | }; |
43 | |||
44 | struct nfc_sock_list { | ||
45 | struct hlist_head head; | ||
46 | rwlock_t lock; | ||
47 | }; | ||
48 | |||
43 | #define nfc_rawsock(sk) ((struct nfc_rawsock *) sk) | 49 | #define nfc_rawsock(sk) ((struct nfc_rawsock *) sk) |
44 | #define to_rawsock_sk(_tx_work) \ | 50 | #define to_rawsock_sk(_tx_work) \ |
45 | ((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work)) | 51 | ((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work)) |
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index c27a6e86cae4..8627c75063e2 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c | |||
@@ -27,6 +27,24 @@ | |||
27 | 27 | ||
28 | #include "nfc.h" | 28 | #include "nfc.h" |
29 | 29 | ||
30 | static struct nfc_sock_list raw_sk_list = { | ||
31 | .lock = __RW_LOCK_UNLOCKED(raw_sk_list.lock) | ||
32 | }; | ||
33 | |||
34 | void nfc_sock_link(struct nfc_sock_list *l, struct sock *sk) | ||
35 | { | ||
36 | write_lock(&l->lock); | ||
37 | sk_add_node(sk, &l->head); | ||
38 | write_unlock(&l->lock); | ||
39 | } | ||
40 | |||
41 | void nfc_sock_unlink(struct nfc_sock_list *l, struct sock *sk) | ||
42 | { | ||
43 | write_lock(&l->lock); | ||
44 | sk_del_node_init(sk); | ||
45 | write_unlock(&l->lock); | ||
46 | } | ||
47 | |||
30 | static void rawsock_write_queue_purge(struct sock *sk) | 48 | static void rawsock_write_queue_purge(struct sock *sk) |
31 | { | 49 | { |
32 | pr_debug("sk=%p\n", sk); | 50 | pr_debug("sk=%p\n", sk); |
@@ -57,6 +75,9 @@ static int rawsock_release(struct socket *sock) | |||
57 | if (!sk) | 75 | if (!sk) |
58 | return 0; | 76 | return 0; |
59 | 77 | ||
78 | if (sock->type == SOCK_RAW) | ||
79 | nfc_sock_unlink(&raw_sk_list, sk); | ||
80 | |||
60 | sock_orphan(sk); | 81 | sock_orphan(sk); |
61 | sock_put(sk); | 82 | sock_put(sk); |
62 | 83 | ||
@@ -275,6 +296,26 @@ static const struct proto_ops rawsock_ops = { | |||
275 | .mmap = sock_no_mmap, | 296 | .mmap = sock_no_mmap, |
276 | }; | 297 | }; |
277 | 298 | ||
299 | static const struct proto_ops rawsock_raw_ops = { | ||
300 | .family = PF_NFC, | ||
301 | .owner = THIS_MODULE, | ||
302 | .release = rawsock_release, | ||
303 | .bind = sock_no_bind, | ||
304 | .connect = sock_no_connect, | ||
305 | .socketpair = sock_no_socketpair, | ||
306 | .accept = sock_no_accept, | ||
307 | .getname = sock_no_getname, | ||
308 | .poll = datagram_poll, | ||
309 | .ioctl = sock_no_ioctl, | ||
310 | .listen = sock_no_listen, | ||
311 | .shutdown = sock_no_shutdown, | ||
312 | .setsockopt = sock_no_setsockopt, | ||
313 | .getsockopt = sock_no_getsockopt, | ||
314 | .sendmsg = sock_no_sendmsg, | ||
315 | .recvmsg = rawsock_recvmsg, | ||
316 | .mmap = sock_no_mmap, | ||
317 | }; | ||
318 | |||
278 | static void rawsock_destruct(struct sock *sk) | 319 | static void rawsock_destruct(struct sock *sk) |
279 | { | 320 | { |
280 | pr_debug("sk=%p\n", sk); | 321 | pr_debug("sk=%p\n", sk); |
@@ -300,10 +341,13 @@ static int rawsock_create(struct net *net, struct socket *sock, | |||
300 | 341 | ||
301 | pr_debug("sock=%p\n", sock); | 342 | pr_debug("sock=%p\n", sock); |
302 | 343 | ||
303 | if (sock->type != SOCK_SEQPACKET) | 344 | if ((sock->type != SOCK_SEQPACKET) && (sock->type != SOCK_RAW)) |
304 | return -ESOCKTNOSUPPORT; | 345 | return -ESOCKTNOSUPPORT; |
305 | 346 | ||
306 | sock->ops = &rawsock_ops; | 347 | if (sock->type == SOCK_RAW) |
348 | sock->ops = &rawsock_raw_ops; | ||
349 | else | ||
350 | sock->ops = &rawsock_ops; | ||
307 | 351 | ||
308 | sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto); | 352 | sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto); |
309 | if (!sk) | 353 | if (!sk) |
@@ -313,13 +357,53 @@ static int rawsock_create(struct net *net, struct socket *sock, | |||
313 | sk->sk_protocol = nfc_proto->id; | 357 | sk->sk_protocol = nfc_proto->id; |
314 | sk->sk_destruct = rawsock_destruct; | 358 | sk->sk_destruct = rawsock_destruct; |
315 | sock->state = SS_UNCONNECTED; | 359 | sock->state = SS_UNCONNECTED; |
316 | 360 | if (sock->type == SOCK_RAW) | |
317 | INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work); | 361 | nfc_sock_link(&raw_sk_list, sk); |
318 | nfc_rawsock(sk)->tx_work_scheduled = false; | 362 | else { |
363 | INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work); | ||
364 | nfc_rawsock(sk)->tx_work_scheduled = false; | ||
365 | } | ||
319 | 366 | ||
320 | return 0; | 367 | return 0; |
321 | } | 368 | } |
322 | 369 | ||
370 | void nfc_send_to_raw_sock(struct nfc_dev *dev, struct sk_buff *skb, | ||
371 | u8 payload_type, u8 direction) | ||
372 | { | ||
373 | struct sk_buff *skb_copy = NULL, *nskb; | ||
374 | struct sock *sk; | ||
375 | u8 *data; | ||
376 | |||
377 | read_lock(&raw_sk_list.lock); | ||
378 | |||
379 | sk_for_each(sk, &raw_sk_list.head) { | ||
380 | if (!skb_copy) { | ||
381 | skb_copy = __pskb_copy(skb, NFC_RAW_HEADER_SIZE, | ||
382 | GFP_ATOMIC); | ||
383 | if (!skb_copy) | ||
384 | continue; | ||
385 | |||
386 | data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE); | ||
387 | |||
388 | data[0] = dev ? dev->idx : 0xFF; | ||
389 | data[1] = direction & 0x01; | ||
390 | data[1] |= (payload_type << 1); | ||
391 | } | ||
392 | |||
393 | nskb = skb_clone(skb_copy, GFP_ATOMIC); | ||
394 | if (!nskb) | ||
395 | continue; | ||
396 | |||
397 | if (sock_queue_rcv_skb(sk, nskb)) | ||
398 | kfree_skb(nskb); | ||
399 | } | ||
400 | |||
401 | read_unlock(&raw_sk_list.lock); | ||
402 | |||
403 | kfree_skb(skb_copy); | ||
404 | } | ||
405 | EXPORT_SYMBOL(nfc_send_to_raw_sock); | ||
406 | |||
323 | static struct proto rawsock_proto = { | 407 | static struct proto rawsock_proto = { |
324 | .name = "NFC_RAW", | 408 | .name = "NFC_RAW", |
325 | .owner = THIS_MODULE, | 409 | .owner = THIS_MODULE, |