aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2015-01-04 11:10:55 -0500
committerMarcel Holtmann <marcel@holtmann.org>2015-01-08 01:25:59 -0500
commit4662a0da544c8ed7ecf79ef0f6c4dc65be081352 (patch)
treef9e36fb6514d41041491dff7b714a80a3f3d98aa /net/ieee802154
parent8691ee592c9299847b28350692eda1d5d6990581 (diff)
ieee802154: 6lowpan: move receive functionality
This patch moves all relevant receive functionality into a separate rx.c file. We can simple separate this functionality like we did it in mac802154. Signed-off-by: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/ieee802154')
-rw-r--r--net/ieee802154/6lowpan/6lowpan_i.h25
-rw-r--r--net/ieee802154/6lowpan/6lowpan_rtnl.c169
-rw-r--r--net/ieee802154/6lowpan/Makefile2
-rw-r--r--net/ieee802154/6lowpan/rx.c171
4 files changed, 200 insertions, 167 deletions
diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
index edbe80314b7d..29ec61b01752 100644
--- a/net/ieee802154/6lowpan/6lowpan_i.h
+++ b/net/ieee802154/6lowpan/6lowpan_i.h
@@ -1,6 +1,8 @@
1#ifndef __IEEE802154_6LOWPAN_I_H__ 1#ifndef __IEEE802154_6LOWPAN_I_H__
2#define __IEEE802154_6LOWPAN_I_H__ 2#define __IEEE802154_6LOWPAN_I_H__
3 3
4#include <linux/list.h>
5
4#include <net/inet_frag.h> 6#include <net/inet_frag.h>
5 7
6struct lowpan_create_arg { 8struct lowpan_create_arg {
@@ -34,8 +36,31 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
34 } 36 }
35} 37}
36 38
39struct lowpan_dev_record {
40 struct net_device *ldev;
41 struct list_head list;
42};
43
44/* private device info */
45struct lowpan_dev_info {
46 struct net_device *real_dev; /* real WPAN device ptr */
47 struct mutex dev_list_mtx; /* mutex for list ops */
48 u16 fragment_tag;
49};
50
51static inline struct
52lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
53{
54 return netdev_priv(dev);
55}
56
57extern struct list_head lowpan_devices;
58
37int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type); 59int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
38void lowpan_net_frag_exit(void); 60void lowpan_net_frag_exit(void);
39int lowpan_net_frag_init(void); 61int lowpan_net_frag_init(void);
40 62
63void lowpan_rx_init(void);
64void lowpan_rx_exit(void);
65
41#endif /* __IEEE802154_6LOWPAN_I_H__ */ 66#endif /* __IEEE802154_6LOWPAN_I_H__ */
diff --git a/net/ieee802154/6lowpan/6lowpan_rtnl.c b/net/ieee802154/6lowpan/6lowpan_rtnl.c
index 1918c43499ce..9dce20e7f6a0 100644
--- a/net/ieee802154/6lowpan/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan/6lowpan_rtnl.c
@@ -57,21 +57,9 @@
57 57
58#include "6lowpan_i.h" 58#include "6lowpan_i.h"
59 59
60static LIST_HEAD(lowpan_devices); 60LIST_HEAD(lowpan_devices);
61static int lowpan_open_count; 61static int lowpan_open_count;
62 62
63/* private device info */
64struct lowpan_dev_info {
65 struct net_device *real_dev; /* real WPAN device ptr */
66 struct mutex dev_list_mtx; /* mutex for list ops */
67 u16 fragment_tag;
68};
69
70struct lowpan_dev_record {
71 struct net_device *ldev;
72 struct list_head list;
73};
74
75/* don't save pan id, it's intra pan */ 63/* don't save pan id, it's intra pan */
76struct lowpan_addr { 64struct lowpan_addr {
77 u8 mode; 65 u8 mode;
@@ -88,12 +76,6 @@ struct lowpan_addr_info {
88}; 76};
89 77
90static inline struct 78static inline struct
91lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
92{
93 return netdev_priv(dev);
94}
95
96static inline struct
97lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb) 79lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
98{ 80{
99 WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info)); 81 WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info));
@@ -134,74 +116,6 @@ static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
134 return 0; 116 return 0;
135} 117}
136 118
137static int lowpan_give_skb_to_devices(struct sk_buff *skb,
138 struct net_device *dev)
139{
140 struct lowpan_dev_record *entry;
141 struct sk_buff *skb_cp;
142 int stat = NET_RX_SUCCESS;
143
144 skb->protocol = htons(ETH_P_IPV6);
145 skb->pkt_type = PACKET_HOST;
146
147 rcu_read_lock();
148 list_for_each_entry_rcu(entry, &lowpan_devices, list)
149 if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
150 skb_cp = skb_copy(skb, GFP_ATOMIC);
151 if (!skb_cp) {
152 kfree_skb(skb);
153 rcu_read_unlock();
154 return NET_RX_DROP;
155 }
156
157 skb_cp->dev = entry->ldev;
158 stat = netif_rx(skb_cp);
159 if (stat == NET_RX_DROP)
160 break;
161 }
162 rcu_read_unlock();
163
164 consume_skb(skb);
165
166 return stat;
167}
168
169static int
170iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
171{
172 u8 iphc0, iphc1;
173 struct ieee802154_addr_sa sa, da;
174 void *sap, *dap;
175
176 raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
177 /* at least two bytes will be used for the encoding */
178 if (skb->len < 2)
179 return -EINVAL;
180
181 if (lowpan_fetch_skb_u8(skb, &iphc0))
182 return -EINVAL;
183
184 if (lowpan_fetch_skb_u8(skb, &iphc1))
185 return -EINVAL;
186
187 ieee802154_addr_to_sa(&sa, &hdr->source);
188 ieee802154_addr_to_sa(&da, &hdr->dest);
189
190 if (sa.addr_type == IEEE802154_ADDR_SHORT)
191 sap = &sa.short_addr;
192 else
193 sap = &sa.hwaddr;
194
195 if (da.addr_type == IEEE802154_ADDR_SHORT)
196 dap = &da.short_addr;
197 else
198 dap = &da.hwaddr;
199
200 return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
201 IEEE802154_ADDR_LEN, dap, da.addr_type,
202 IEEE802154_ADDR_LEN, iphc0, iphc1);
203}
204
205static struct sk_buff* 119static struct sk_buff*
206lowpan_alloc_frag(struct sk_buff *skb, int size, 120lowpan_alloc_frag(struct sk_buff *skb, int size,
207 const struct ieee802154_hdr *master_hdr) 121 const struct ieee802154_hdr *master_hdr)
@@ -485,83 +399,6 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
485 return 0; 399 return 0;
486} 400}
487 401
488static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
489 struct packet_type *pt, struct net_device *orig_dev)
490{
491 struct ieee802154_hdr hdr;
492 int ret;
493
494 skb = skb_share_check(skb, GFP_ATOMIC);
495 if (!skb)
496 goto drop;
497
498 if (!netif_running(dev))
499 goto drop_skb;
500
501 if (skb->pkt_type == PACKET_OTHERHOST)
502 goto drop_skb;
503
504 if (dev->type != ARPHRD_IEEE802154)
505 goto drop_skb;
506
507 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
508 goto drop_skb;
509
510 /* check that it's our buffer */
511 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
512 /* Pull off the 1-byte of 6lowpan header. */
513 skb_pull(skb, 1);
514 return lowpan_give_skb_to_devices(skb, NULL);
515 } else {
516 switch (skb->data[0] & 0xe0) {
517 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
518 ret = iphc_decompress(skb, &hdr);
519 if (ret < 0)
520 goto drop_skb;
521
522 return lowpan_give_skb_to_devices(skb, NULL);
523 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
524 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
525 if (ret == 1) {
526 ret = iphc_decompress(skb, &hdr);
527 if (ret < 0)
528 goto drop_skb;
529
530 return lowpan_give_skb_to_devices(skb, NULL);
531 } else if (ret == -1) {
532 return NET_RX_DROP;
533 } else {
534 return NET_RX_SUCCESS;
535 }
536 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
537 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
538 if (ret == 1) {
539 ret = iphc_decompress(skb, &hdr);
540 if (ret < 0)
541 goto drop_skb;
542
543 return lowpan_give_skb_to_devices(skb, NULL);
544 } else if (ret == -1) {
545 return NET_RX_DROP;
546 } else {
547 return NET_RX_SUCCESS;
548 }
549 default:
550 break;
551 }
552 }
553
554drop_skb:
555 kfree_skb(skb);
556drop:
557 return NET_RX_DROP;
558}
559
560static struct packet_type lowpan_packet_type = {
561 .type = htons(ETH_P_IEEE802154),
562 .func = lowpan_rcv,
563};
564
565static int lowpan_newlink(struct net *src_net, struct net_device *dev, 402static int lowpan_newlink(struct net *src_net, struct net_device *dev,
566 struct nlattr *tb[], struct nlattr *data[]) 403 struct nlattr *tb[], struct nlattr *data[])
567{ 404{
@@ -607,7 +444,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
607 ret = register_netdevice(dev); 444 ret = register_netdevice(dev);
608 if (ret >= 0) { 445 if (ret >= 0) {
609 if (!lowpan_open_count) 446 if (!lowpan_open_count)
610 dev_add_pack(&lowpan_packet_type); 447 lowpan_rx_init();
611 lowpan_open_count++; 448 lowpan_open_count++;
612 } 449 }
613 450
@@ -624,7 +461,7 @@ static void lowpan_dellink(struct net_device *dev, struct list_head *head)
624 461
625 lowpan_open_count--; 462 lowpan_open_count--;
626 if (!lowpan_open_count) 463 if (!lowpan_open_count)
627 dev_remove_pack(&lowpan_packet_type); 464 lowpan_rx_exit();
628 465
629 mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx); 466 mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
630 list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) { 467 list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
diff --git a/net/ieee802154/6lowpan/Makefile b/net/ieee802154/6lowpan/Makefile
index 936959bd4f99..8e8397185751 100644
--- a/net/ieee802154/6lowpan/Makefile
+++ b/net/ieee802154/6lowpan/Makefile
@@ -1,3 +1,3 @@
1obj-y += ieee802154_6lowpan.o 1obj-y += ieee802154_6lowpan.o
2 2
3ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o 3ieee802154_6lowpan-y := 6lowpan_rtnl.o rx.o reassembly.o
diff --git a/net/ieee802154/6lowpan/rx.c b/net/ieee802154/6lowpan/rx.c
new file mode 100644
index 000000000000..4be1d289ab2d
--- /dev/null
+++ b/net/ieee802154/6lowpan/rx.c
@@ -0,0 +1,171 @@
1/* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License version 2
3 * as published by the Free Software Foundation.
4 *
5 * This program is distributed in the hope that it will be useful,
6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 * GNU General Public License for more details.
9 */
10
11#include <linux/if_arp.h>
12
13#include <net/6lowpan.h>
14#include <net/ieee802154_netdev.h>
15
16#include "6lowpan_i.h"
17
18static int lowpan_give_skb_to_devices(struct sk_buff *skb,
19 struct net_device *dev)
20{
21 struct lowpan_dev_record *entry;
22 struct sk_buff *skb_cp;
23 int stat = NET_RX_SUCCESS;
24
25 skb->protocol = htons(ETH_P_IPV6);
26 skb->pkt_type = PACKET_HOST;
27
28 rcu_read_lock();
29 list_for_each_entry_rcu(entry, &lowpan_devices, list)
30 if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
31 skb_cp = skb_copy(skb, GFP_ATOMIC);
32 if (!skb_cp) {
33 kfree_skb(skb);
34 rcu_read_unlock();
35 return NET_RX_DROP;
36 }
37
38 skb_cp->dev = entry->ldev;
39 stat = netif_rx(skb_cp);
40 if (stat == NET_RX_DROP)
41 break;
42 }
43 rcu_read_unlock();
44
45 consume_skb(skb);
46
47 return stat;
48}
49
50static int
51iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
52{
53 u8 iphc0, iphc1;
54 struct ieee802154_addr_sa sa, da;
55 void *sap, *dap;
56
57 raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
58 /* at least two bytes will be used for the encoding */
59 if (skb->len < 2)
60 return -EINVAL;
61
62 if (lowpan_fetch_skb_u8(skb, &iphc0))
63 return -EINVAL;
64
65 if (lowpan_fetch_skb_u8(skb, &iphc1))
66 return -EINVAL;
67
68 ieee802154_addr_to_sa(&sa, &hdr->source);
69 ieee802154_addr_to_sa(&da, &hdr->dest);
70
71 if (sa.addr_type == IEEE802154_ADDR_SHORT)
72 sap = &sa.short_addr;
73 else
74 sap = &sa.hwaddr;
75
76 if (da.addr_type == IEEE802154_ADDR_SHORT)
77 dap = &da.short_addr;
78 else
79 dap = &da.hwaddr;
80
81 return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
82 IEEE802154_ADDR_LEN, dap, da.addr_type,
83 IEEE802154_ADDR_LEN, iphc0, iphc1);
84}
85
86static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
87 struct packet_type *pt, struct net_device *orig_dev)
88{
89 struct ieee802154_hdr hdr;
90 int ret;
91
92 skb = skb_share_check(skb, GFP_ATOMIC);
93 if (!skb)
94 goto drop;
95
96 if (!netif_running(dev))
97 goto drop_skb;
98
99 if (skb->pkt_type == PACKET_OTHERHOST)
100 goto drop_skb;
101
102 if (dev->type != ARPHRD_IEEE802154)
103 goto drop_skb;
104
105 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
106 goto drop_skb;
107
108 /* check that it's our buffer */
109 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
110 /* Pull off the 1-byte of 6lowpan header. */
111 skb_pull(skb, 1);
112 return lowpan_give_skb_to_devices(skb, NULL);
113 } else {
114 switch (skb->data[0] & 0xe0) {
115 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
116 ret = iphc_decompress(skb, &hdr);
117 if (ret < 0)
118 goto drop_skb;
119
120 return lowpan_give_skb_to_devices(skb, NULL);
121 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
122 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
123 if (ret == 1) {
124 ret = iphc_decompress(skb, &hdr);
125 if (ret < 0)
126 goto drop_skb;
127
128 return lowpan_give_skb_to_devices(skb, NULL);
129 } else if (ret == -1) {
130 return NET_RX_DROP;
131 } else {
132 return NET_RX_SUCCESS;
133 }
134 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
135 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
136 if (ret == 1) {
137 ret = iphc_decompress(skb, &hdr);
138 if (ret < 0)
139 goto drop_skb;
140
141 return lowpan_give_skb_to_devices(skb, NULL);
142 } else if (ret == -1) {
143 return NET_RX_DROP;
144 } else {
145 return NET_RX_SUCCESS;
146 }
147 default:
148 break;
149 }
150 }
151
152drop_skb:
153 kfree_skb(skb);
154drop:
155 return NET_RX_DROP;
156}
157
158static struct packet_type lowpan_packet_type = {
159 .type = htons(ETH_P_IEEE802154),
160 .func = lowpan_rcv,
161};
162
163void lowpan_rx_init(void)
164{
165 dev_add_pack(&lowpan_packet_type);
166}
167
168void lowpan_rx_exit(void)
169{
170 dev_remove_pack(&lowpan_packet_type);
171}