diff options
author | Alexander Aring <alex.aring@gmail.com> | 2015-01-04 11:10:55 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-01-08 01:25:59 -0500 |
commit | 4662a0da544c8ed7ecf79ef0f6c4dc65be081352 (patch) | |
tree | f9e36fb6514d41041491dff7b714a80a3f3d98aa /net/ieee802154 | |
parent | 8691ee592c9299847b28350692eda1d5d6990581 (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.h | 25 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/6lowpan_rtnl.c | 169 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/Makefile | 2 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/rx.c | 171 |
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 | ||
6 | struct lowpan_create_arg { | 8 | struct lowpan_create_arg { |
@@ -34,8 +36,31 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) | |||
34 | } | 36 | } |
35 | } | 37 | } |
36 | 38 | ||
39 | struct lowpan_dev_record { | ||
40 | struct net_device *ldev; | ||
41 | struct list_head list; | ||
42 | }; | ||
43 | |||
44 | /* private device info */ | ||
45 | struct 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 | |||
51 | static inline struct | ||
52 | lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) | ||
53 | { | ||
54 | return netdev_priv(dev); | ||
55 | } | ||
56 | |||
57 | extern struct list_head lowpan_devices; | ||
58 | |||
37 | int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type); | 59 | int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type); |
38 | void lowpan_net_frag_exit(void); | 60 | void lowpan_net_frag_exit(void); |
39 | int lowpan_net_frag_init(void); | 61 | int lowpan_net_frag_init(void); |
40 | 62 | ||
63 | void lowpan_rx_init(void); | ||
64 | void 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 | ||
60 | static LIST_HEAD(lowpan_devices); | 60 | LIST_HEAD(lowpan_devices); |
61 | static int lowpan_open_count; | 61 | static int lowpan_open_count; |
62 | 62 | ||
63 | /* private device info */ | ||
64 | struct 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 | |||
70 | struct 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 */ |
76 | struct lowpan_addr { | 64 | struct lowpan_addr { |
77 | u8 mode; | 65 | u8 mode; |
@@ -88,12 +76,6 @@ struct lowpan_addr_info { | |||
88 | }; | 76 | }; |
89 | 77 | ||
90 | static inline struct | 78 | static inline struct |
91 | lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) | ||
92 | { | ||
93 | return netdev_priv(dev); | ||
94 | } | ||
95 | |||
96 | static inline struct | ||
97 | lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb) | 79 | lowpan_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 | ||
137 | static 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 | |||
169 | static int | ||
170 | iphc_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 | |||
205 | static struct sk_buff* | 119 | static struct sk_buff* |
206 | lowpan_alloc_frag(struct sk_buff *skb, int size, | 120 | lowpan_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 | ||
488 | static 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 | |||
554 | drop_skb: | ||
555 | kfree_skb(skb); | ||
556 | drop: | ||
557 | return NET_RX_DROP; | ||
558 | } | ||
559 | |||
560 | static struct packet_type lowpan_packet_type = { | ||
561 | .type = htons(ETH_P_IEEE802154), | ||
562 | .func = lowpan_rcv, | ||
563 | }; | ||
564 | |||
565 | static int lowpan_newlink(struct net *src_net, struct net_device *dev, | 402 | static 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 @@ | |||
1 | obj-y += ieee802154_6lowpan.o | 1 | obj-y += ieee802154_6lowpan.o |
2 | 2 | ||
3 | ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o | 3 | ieee802154_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 | |||
18 | static 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 | |||
50 | static int | ||
51 | iphc_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 | |||
86 | static 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 | |||
152 | drop_skb: | ||
153 | kfree_skb(skb); | ||
154 | drop: | ||
155 | return NET_RX_DROP; | ||
156 | } | ||
157 | |||
158 | static struct packet_type lowpan_packet_type = { | ||
159 | .type = htons(ETH_P_IEEE802154), | ||
160 | .func = lowpan_rcv, | ||
161 | }; | ||
162 | |||
163 | void lowpan_rx_init(void) | ||
164 | { | ||
165 | dev_add_pack(&lowpan_packet_type); | ||
166 | } | ||
167 | |||
168 | void lowpan_rx_exit(void) | ||
169 | { | ||
170 | dev_remove_pack(&lowpan_packet_type); | ||
171 | } | ||