aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154/6lowpan_rtnl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee802154/6lowpan_rtnl.c')
-rw-r--r--net/ieee802154/6lowpan_rtnl.c256
1 files changed, 49 insertions, 207 deletions
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index f9c954824ddb..c7bd8b55f7ce 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -54,6 +54,7 @@
54#include <net/ieee802154_netdev.h> 54#include <net/ieee802154_netdev.h>
55#include <net/ipv6.h> 55#include <net/ipv6.h>
56 56
57#include "reassembly.h"
57#include "6lowpan.h" 58#include "6lowpan.h"
58 59
59static LIST_HEAD(lowpan_devices); 60static LIST_HEAD(lowpan_devices);
@@ -70,18 +71,6 @@ struct lowpan_dev_record {
70 struct list_head list; 71 struct list_head list;
71}; 72};
72 73
73struct lowpan_fragment {
74 struct sk_buff *skb; /* skb to be assembled */
75 u16 length; /* length to be assemled */
76 u32 bytes_rcv; /* bytes received */
77 u16 tag; /* current fragment tag */
78 struct timer_list timer; /* assembling timer */
79 struct list_head list; /* fragments list */
80};
81
82static LIST_HEAD(lowpan_fragments);
83static DEFINE_SPINLOCK(flist_lock);
84
85static inline struct 74static inline struct
86lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) 75lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
87{ 76{
@@ -179,69 +168,6 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb,
179 return stat; 168 return stat;
180} 169}
181 170
182static void lowpan_fragment_timer_expired(unsigned long entry_addr)
183{
184 struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
185
186 pr_debug("timer expired for frame with tag %d\n", entry->tag);
187
188 list_del(&entry->list);
189 dev_kfree_skb(entry->skb);
190 kfree(entry);
191}
192
193static struct lowpan_fragment *
194lowpan_alloc_new_frame(struct sk_buff *skb, u16 len, u16 tag)
195{
196 struct lowpan_fragment *frame;
197
198 frame = kzalloc(sizeof(struct lowpan_fragment),
199 GFP_ATOMIC);
200 if (!frame)
201 goto frame_err;
202
203 INIT_LIST_HEAD(&frame->list);
204
205 frame->length = len;
206 frame->tag = tag;
207
208 /* allocate buffer for frame assembling */
209 frame->skb = netdev_alloc_skb_ip_align(skb->dev, frame->length +
210 sizeof(struct ipv6hdr));
211
212 if (!frame->skb)
213 goto skb_err;
214
215 frame->skb->priority = skb->priority;
216
217 /* reserve headroom for uncompressed ipv6 header */
218 skb_reserve(frame->skb, sizeof(struct ipv6hdr));
219 skb_put(frame->skb, frame->length);
220
221 /* copy the first control block to keep a
222 * trace of the link-layer addresses in case
223 * of a link-local compressed address
224 */
225 memcpy(frame->skb->cb, skb->cb, sizeof(skb->cb));
226
227 init_timer(&frame->timer);
228 /* time out is the same as for ipv6 - 60 sec */
229 frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
230 frame->timer.data = (unsigned long)frame;
231 frame->timer.function = lowpan_fragment_timer_expired;
232
233 add_timer(&frame->timer);
234
235 list_add_tail(&frame->list, &lowpan_fragments);
236
237 return frame;
238
239skb_err:
240 kfree(frame);
241frame_err:
242 return NULL;
243}
244
245static int process_data(struct sk_buff *skb) 171static int process_data(struct sk_buff *skb)
246{ 172{
247 u8 iphc0, iphc1; 173 u8 iphc0, iphc1;
@@ -255,94 +181,6 @@ static int process_data(struct sk_buff *skb)
255 if (lowpan_fetch_skb_u8(skb, &iphc0)) 181 if (lowpan_fetch_skb_u8(skb, &iphc0))
256 goto drop; 182 goto drop;
257 183
258 /* fragments assembling */
259 switch (iphc0 & LOWPAN_DISPATCH_MASK) {
260 case LOWPAN_DISPATCH_FRAG1:
261 case LOWPAN_DISPATCH_FRAGN:
262 {
263 struct lowpan_fragment *frame;
264 /* slen stores the rightmost 8 bits of the 11 bits length */
265 u8 slen, offset = 0;
266 u16 len, tag;
267 bool found = false;
268
269 if (lowpan_fetch_skb_u8(skb, &slen) || /* frame length */
270 lowpan_fetch_skb_u16(skb, &tag)) /* fragment tag */
271 goto drop;
272
273 /* adds the 3 MSB to the 8 LSB to retrieve the 11 bits length */
274 len = ((iphc0 & 7) << 8) | slen;
275
276 if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) {
277 pr_debug("%s received a FRAG1 packet (tag: %d, "
278 "size of the entire IP packet: %d)",
279 __func__, tag, len);
280 } else { /* FRAGN */
281 if (lowpan_fetch_skb_u8(skb, &offset))
282 goto unlock_and_drop;
283 pr_debug("%s received a FRAGN packet (tag: %d, "
284 "size of the entire IP packet: %d, "
285 "offset: %d)", __func__, tag, len, offset * 8);
286 }
287
288 /*
289 * check if frame assembling with the same tag is
290 * already in progress
291 */
292 spin_lock_bh(&flist_lock);
293
294 list_for_each_entry(frame, &lowpan_fragments, list)
295 if (frame->tag == tag) {
296 found = true;
297 break;
298 }
299
300 /* alloc new frame structure */
301 if (!found) {
302 pr_debug("%s first fragment received for tag %d, "
303 "begin packet reassembly", __func__, tag);
304 frame = lowpan_alloc_new_frame(skb, len, tag);
305 if (!frame)
306 goto unlock_and_drop;
307 }
308
309 /* if payload fits buffer, copy it */
310 if (likely((offset * 8 + skb->len) <= frame->length))
311 skb_copy_to_linear_data_offset(frame->skb, offset * 8,
312 skb->data, skb->len);
313 else
314 goto unlock_and_drop;
315
316 frame->bytes_rcv += skb->len;
317
318 /* frame assembling complete */
319 if ((frame->bytes_rcv == frame->length) &&
320 frame->timer.expires > jiffies) {
321 /* if timer haven't expired - first of all delete it */
322 del_timer_sync(&frame->timer);
323 list_del(&frame->list);
324 spin_unlock_bh(&flist_lock);
325
326 pr_debug("%s successfully reassembled fragment "
327 "(tag %d)", __func__, tag);
328
329 dev_kfree_skb(skb);
330 skb = frame->skb;
331 kfree(frame);
332
333 if (lowpan_fetch_skb_u8(skb, &iphc0))
334 goto drop;
335
336 break;
337 }
338 spin_unlock_bh(&flist_lock);
339
340 return kfree_skb(skb), 0;
341 }
342 default:
343 break;
344 }
345
346 if (lowpan_fetch_skb_u8(skb, &iphc1)) 184 if (lowpan_fetch_skb_u8(skb, &iphc1))
347 goto drop; 185 goto drop;
348 186
@@ -355,8 +193,6 @@ static int process_data(struct sk_buff *skb)
355 IEEE802154_ADDR_LEN, iphc0, iphc1, 193 IEEE802154_ADDR_LEN, iphc0, iphc1,
356 lowpan_give_skb_to_devices); 194 lowpan_give_skb_to_devices);
357 195
358unlock_and_drop:
359 spin_unlock_bh(&flist_lock);
360drop: 196drop:
361 kfree_skb(skb); 197 kfree_skb(skb);
362 return -EINVAL; 198 return -EINVAL;
@@ -603,44 +439,53 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
603 struct packet_type *pt, struct net_device *orig_dev) 439 struct packet_type *pt, struct net_device *orig_dev)
604{ 440{
605 struct sk_buff *local_skb; 441 struct sk_buff *local_skb;
442 int ret;
606 443
607 if (!netif_running(dev)) 444 if (!netif_running(dev))
608 goto drop; 445 goto drop_skb;
609 446
610 if (dev->type != ARPHRD_IEEE802154) 447 if (dev->type != ARPHRD_IEEE802154)
611 goto drop; 448 goto drop_skb;
449
450 local_skb = skb_clone(skb, GFP_ATOMIC);
451 if (!local_skb)
452 goto drop_skb;
453
454 kfree_skb(skb);
612 455
613 /* check that it's our buffer */ 456 /* check that it's our buffer */
614 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { 457 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
615 /* Copy the packet so that the IPv6 header is
616 * properly aligned.
617 */
618 local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
619 skb_tailroom(skb), GFP_ATOMIC);
620 if (!local_skb)
621 goto drop;
622
623 local_skb->protocol = htons(ETH_P_IPV6); 458 local_skb->protocol = htons(ETH_P_IPV6);
624 local_skb->pkt_type = PACKET_HOST; 459 local_skb->pkt_type = PACKET_HOST;
625 460
626 /* Pull off the 1-byte of 6lowpan header. */ 461 /* Pull off the 1-byte of 6lowpan header. */
627 skb_pull(local_skb, 1); 462 skb_pull(local_skb, 1);
628 463
629 lowpan_give_skb_to_devices(local_skb, NULL); 464 ret = lowpan_give_skb_to_devices(local_skb, NULL);
630 465 if (ret == NET_RX_DROP)
631 kfree_skb(local_skb); 466 goto drop;
632 kfree_skb(skb);
633 } else { 467 } else {
634 switch (skb->data[0] & 0xe0) { 468 switch (skb->data[0] & 0xe0) {
635 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ 469 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
470 ret = process_data(local_skb);
471 if (ret == NET_RX_DROP)
472 goto drop;
473 break;
636 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ 474 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
475 ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1);
476 if (ret == 1) {
477 ret = process_data(local_skb);
478 if (ret == NET_RX_DROP)
479 goto drop;
480 }
481 break;
637 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ 482 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
638 local_skb = skb_clone(skb, GFP_ATOMIC); 483 ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN);
639 if (!local_skb) 484 if (ret == 1) {
640 goto drop; 485 ret = process_data(local_skb);
641 process_data(local_skb); 486 if (ret == NET_RX_DROP)
642 487 goto drop;
643 kfree_skb(skb); 488 }
644 break; 489 break;
645 default: 490 default:
646 break; 491 break;
@@ -648,9 +493,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
648 } 493 }
649 494
650 return NET_RX_SUCCESS; 495 return NET_RX_SUCCESS;
651 496drop_skb:
652drop:
653 kfree_skb(skb); 497 kfree_skb(skb);
498drop:
654 return NET_RX_DROP; 499 return NET_RX_DROP;
655} 500}
656 501
@@ -778,43 +623,40 @@ static int __init lowpan_init_module(void)
778{ 623{
779 int err = 0; 624 int err = 0;
780 625
781 err = lowpan_netlink_init(); 626 err = lowpan_net_frag_init();
782 if (err < 0) 627 if (err < 0)
783 goto out; 628 goto out;
784 629
630 err = lowpan_netlink_init();
631 if (err < 0)
632 goto out_frag;
633
785 dev_add_pack(&lowpan_packet_type); 634 dev_add_pack(&lowpan_packet_type);
786 635
787 err = register_netdevice_notifier(&lowpan_dev_notifier); 636 err = register_netdevice_notifier(&lowpan_dev_notifier);
788 if (err < 0) { 637 if (err < 0)
789 dev_remove_pack(&lowpan_packet_type); 638 goto out_pack;
790 lowpan_netlink_fini(); 639
791 } 640 return 0;
641
642out_pack:
643 dev_remove_pack(&lowpan_packet_type);
644 lowpan_netlink_fini();
645out_frag:
646 lowpan_net_frag_exit();
792out: 647out:
793 return err; 648 return err;
794} 649}
795 650
796static void __exit lowpan_cleanup_module(void) 651static void __exit lowpan_cleanup_module(void)
797{ 652{
798 struct lowpan_fragment *frame, *tframe;
799
800 lowpan_netlink_fini(); 653 lowpan_netlink_fini();
801 654
802 dev_remove_pack(&lowpan_packet_type); 655 dev_remove_pack(&lowpan_packet_type);
803 656
804 unregister_netdevice_notifier(&lowpan_dev_notifier); 657 lowpan_net_frag_exit();
805 658
806 /* Now 6lowpan packet_type is removed, so no new fragments are 659 unregister_netdevice_notifier(&lowpan_dev_notifier);
807 * expected on RX, therefore that's the time to clean incomplete
808 * fragments.
809 */
810 spin_lock_bh(&flist_lock);
811 list_for_each_entry_safe(frame, tframe, &lowpan_fragments, list) {
812 del_timer_sync(&frame->timer);
813 list_del(&frame->list);
814 dev_kfree_skb(frame->skb);
815 kfree(frame);
816 }
817 spin_unlock_bh(&flist_lock);
818} 660}
819 661
820module_init(lowpan_init_module); 662module_init(lowpan_init_module);