aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154/6lowpan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee802154/6lowpan.c')
-rw-r--r--net/ieee802154/6lowpan.c374
1 files changed, 361 insertions, 13 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 19d6aefe97d4..e4ecc1eef98c 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -50,8 +50,6 @@
50 * SUCH DAMAGE. 50 * SUCH DAMAGE.
51 */ 51 */
52 52
53#define DEBUG
54
55#include <linux/bitops.h> 53#include <linux/bitops.h>
56#include <linux/if_arp.h> 54#include <linux/if_arp.h>
57#include <linux/module.h> 55#include <linux/module.h>
@@ -113,6 +111,20 @@ struct lowpan_dev_record {
113 struct list_head list; 111 struct list_head list;
114}; 112};
115 113
114struct lowpan_fragment {
115 struct sk_buff *skb; /* skb to be assembled */
116 spinlock_t lock; /* concurency lock */
117 u16 length; /* length to be assemled */
118 u32 bytes_rcv; /* bytes received */
119 u16 tag; /* current fragment tag */
120 struct timer_list timer; /* assembling timer */
121 struct list_head list; /* fragments list */
122};
123
124static unsigned short fragment_tag;
125static LIST_HEAD(lowpan_fragments);
126spinlock_t flist_lock;
127
116static inline struct 128static inline struct
117lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) 129lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
118{ 130{
@@ -234,6 +246,50 @@ lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
234 return 0; 246 return 0;
235} 247}
236 248
249static void
250lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
251{
252 struct udphdr *uh = udp_hdr(skb);
253
254 pr_debug("(%s): UDP header compression\n", __func__);
255
256 if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) ==
257 LOWPAN_NHC_UDP_4BIT_PORT) &&
258 ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) ==
259 LOWPAN_NHC_UDP_4BIT_PORT)) {
260 pr_debug("(%s): both ports compression to 4 bits\n", __func__);
261 **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
262 **(hc06_ptr + 1) = /* subtraction is faster */
263 (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) +
264 ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4));
265 *hc06_ptr += 2;
266 } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) ==
267 LOWPAN_NHC_UDP_8BIT_PORT) {
268 pr_debug("(%s): remove 8 bits of dest\n", __func__);
269 **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
270 memcpy(*hc06_ptr + 1, &uh->source, 2);
271 **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT);
272 *hc06_ptr += 4;
273 } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) ==
274 LOWPAN_NHC_UDP_8BIT_PORT) {
275 pr_debug("(%s): remove 8 bits of source\n", __func__);
276 **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
277 memcpy(*hc06_ptr + 1, &uh->dest, 2);
278 **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT);
279 *hc06_ptr += 4;
280 } else {
281 pr_debug("(%s): can't compress header\n", __func__);
282 **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
283 memcpy(*hc06_ptr + 1, &uh->source, 2);
284 memcpy(*hc06_ptr + 3, &uh->dest, 2);
285 *hc06_ptr += 5;
286 }
287
288 /* checksum is always inline */
289 memcpy(*hc06_ptr, &uh->check, 2);
290 *hc06_ptr += 2;
291}
292
237static u8 lowpan_fetch_skb_u8(struct sk_buff *skb) 293static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
238{ 294{
239 u8 ret; 295 u8 ret;
@@ -244,6 +300,73 @@ static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
244 return ret; 300 return ret;
245} 301}
246 302
303static u16 lowpan_fetch_skb_u16(struct sk_buff *skb)
304{
305 u16 ret;
306
307 BUG_ON(!pskb_may_pull(skb, 2));
308
309 ret = skb->data[0] | (skb->data[1] << 8);
310 skb_pull(skb, 2);
311 return ret;
312}
313
314static int
315lowpan_uncompress_udp_header(struct sk_buff *skb)
316{
317 struct udphdr *uh = udp_hdr(skb);
318 u8 tmp;
319
320 tmp = lowpan_fetch_skb_u8(skb);
321
322 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
323 pr_debug("(%s): UDP header uncompression\n", __func__);
324 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
325 case LOWPAN_NHC_UDP_CS_P_00:
326 memcpy(&uh->source, &skb->data[0], 2);
327 memcpy(&uh->dest, &skb->data[2], 2);
328 skb_pull(skb, 4);
329 break;
330 case LOWPAN_NHC_UDP_CS_P_01:
331 memcpy(&uh->source, &skb->data[0], 2);
332 uh->dest =
333 skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT;
334 skb_pull(skb, 3);
335 break;
336 case LOWPAN_NHC_UDP_CS_P_10:
337 uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT;
338 memcpy(&uh->dest, &skb->data[1], 2);
339 skb_pull(skb, 3);
340 break;
341 case LOWPAN_NHC_UDP_CS_P_11:
342 uh->source =
343 LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4);
344 uh->dest =
345 LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f);
346 skb_pull(skb, 1);
347 break;
348 default:
349 pr_debug("(%s) ERROR: unknown UDP format\n", __func__);
350 goto err;
351 break;
352 }
353
354 pr_debug("(%s): uncompressed UDP ports: src = %d, dst = %d\n",
355 __func__, uh->source, uh->dest);
356
357 /* copy checksum */
358 memcpy(&uh->check, &skb->data[0], 2);
359 skb_pull(skb, 2);
360 } else {
361 pr_debug("(%s): ERROR: unsupported NH format\n", __func__);
362 goto err;
363 }
364
365 return 0;
366err:
367 return -EINVAL;
368}
369
247static int lowpan_header_create(struct sk_buff *skb, 370static int lowpan_header_create(struct sk_buff *skb,
248 struct net_device *dev, 371 struct net_device *dev,
249 unsigned short type, const void *_daddr, 372 unsigned short type, const void *_daddr,
@@ -342,8 +465,6 @@ static int lowpan_header_create(struct sk_buff *skb,
342 if (hdr->nexthdr == UIP_PROTO_UDP) 465 if (hdr->nexthdr == UIP_PROTO_UDP)
343 iphc0 |= LOWPAN_IPHC_NH_C; 466 iphc0 |= LOWPAN_IPHC_NH_C;
344 467
345/* TODO: next header compression */
346
347 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { 468 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
348 *hc06_ptr = hdr->nexthdr; 469 *hc06_ptr = hdr->nexthdr;
349 hc06_ptr += 1; 470 hc06_ptr += 1;
@@ -431,8 +552,9 @@ static int lowpan_header_create(struct sk_buff *skb,
431 } 552 }
432 } 553 }
433 554
434 /* TODO: UDP header compression */ 555 /* UDP header compression */
435 /* TODO: Next Header compression */ 556 if (hdr->nexthdr == UIP_PROTO_UDP)
557 lowpan_compress_udp_header(&hc06_ptr, skb);
436 558
437 head[0] = iphc0; 559 head[0] = iphc0;
438 head[1] = iphc1; 560 head[1] = iphc1;
@@ -467,6 +589,7 @@ static int lowpan_header_create(struct sk_buff *skb,
467 memcpy(&(sa.hwaddr), saddr, 8); 589 memcpy(&(sa.hwaddr), saddr, 8);
468 590
469 mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; 591 mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
592
470 return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, 593 return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
471 type, (void *)&da, (void *)&sa, skb->len); 594 type, (void *)&da, (void *)&sa, skb->len);
472 } 595 }
@@ -511,6 +634,21 @@ static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
511 return stat; 634 return stat;
512} 635}
513 636
637static void lowpan_fragment_timer_expired(unsigned long entry_addr)
638{
639 struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
640
641 pr_debug("%s: timer expired for frame with tag %d\n", __func__,
642 entry->tag);
643
644 spin_lock(&flist_lock);
645 list_del(&entry->list);
646 spin_unlock(&flist_lock);
647
648 dev_kfree_skb(entry->skb);
649 kfree(entry);
650}
651
514static int 652static int
515lowpan_process_data(struct sk_buff *skb) 653lowpan_process_data(struct sk_buff *skb)
516{ 654{
@@ -525,6 +663,107 @@ lowpan_process_data(struct sk_buff *skb)
525 if (skb->len < 2) 663 if (skb->len < 2)
526 goto drop; 664 goto drop;
527 iphc0 = lowpan_fetch_skb_u8(skb); 665 iphc0 = lowpan_fetch_skb_u8(skb);
666
667 /* fragments assembling */
668 switch (iphc0 & LOWPAN_DISPATCH_MASK) {
669 case LOWPAN_DISPATCH_FRAG1:
670 case LOWPAN_DISPATCH_FRAGN:
671 {
672 struct lowpan_fragment *frame;
673 u8 len, offset;
674 u16 tag;
675 bool found = false;
676
677 len = lowpan_fetch_skb_u8(skb); /* frame length */
678 tag = lowpan_fetch_skb_u16(skb);
679
680 /*
681 * check if frame assembling with the same tag is
682 * already in progress
683 */
684 spin_lock(&flist_lock);
685
686 list_for_each_entry(frame, &lowpan_fragments, list)
687 if (frame->tag == tag) {
688 found = true;
689 break;
690 }
691
692 /* alloc new frame structure */
693 if (!found) {
694 frame = kzalloc(sizeof(struct lowpan_fragment),
695 GFP_ATOMIC);
696 if (!frame)
697 goto unlock_and_drop;
698
699 INIT_LIST_HEAD(&frame->list);
700
701 frame->length = (iphc0 & 7) | (len << 3);
702 frame->tag = tag;
703
704 /* allocate buffer for frame assembling */
705 frame->skb = alloc_skb(frame->length +
706 sizeof(struct ipv6hdr), GFP_ATOMIC);
707
708 if (!frame->skb) {
709 kfree(frame);
710 goto unlock_and_drop;
711 }
712
713 frame->skb->priority = skb->priority;
714 frame->skb->dev = skb->dev;
715
716 /* reserve headroom for uncompressed ipv6 header */
717 skb_reserve(frame->skb, sizeof(struct ipv6hdr));
718 skb_put(frame->skb, frame->length);
719
720 init_timer(&frame->timer);
721 /* time out is the same as for ipv6 - 60 sec */
722 frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
723 frame->timer.data = (unsigned long)frame;
724 frame->timer.function = lowpan_fragment_timer_expired;
725
726 add_timer(&frame->timer);
727
728 list_add_tail(&frame->list, &lowpan_fragments);
729 }
730
731 if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
732 goto unlock_and_drop;
733
734 offset = lowpan_fetch_skb_u8(skb); /* fetch offset */
735
736 /* if payload fits buffer, copy it */
737 if (likely((offset * 8 + skb->len) <= frame->length))
738 skb_copy_to_linear_data_offset(frame->skb, offset * 8,
739 skb->data, skb->len);
740 else
741 goto unlock_and_drop;
742
743 frame->bytes_rcv += skb->len;
744
745 /* frame assembling complete */
746 if ((frame->bytes_rcv == frame->length) &&
747 frame->timer.expires > jiffies) {
748 /* if timer haven't expired - first of all delete it */
749 del_timer(&frame->timer);
750 list_del(&frame->list);
751 spin_unlock(&flist_lock);
752
753 dev_kfree_skb(skb);
754 skb = frame->skb;
755 kfree(frame);
756 iphc0 = lowpan_fetch_skb_u8(skb);
757 break;
758 }
759 spin_unlock(&flist_lock);
760
761 return kfree_skb(skb), 0;
762 }
763 default:
764 break;
765 }
766
528 iphc1 = lowpan_fetch_skb_u8(skb); 767 iphc1 = lowpan_fetch_skb_u8(skb);
529 768
530 _saddr = mac_cb(skb)->sa.hwaddr; 769 _saddr = mac_cb(skb)->sa.hwaddr;
@@ -659,7 +898,10 @@ lowpan_process_data(struct sk_buff *skb)
659 goto drop; 898 goto drop;
660 } 899 }
661 900
662 /* TODO: UDP header parse */ 901 /* UDP data uncompression */
902 if (iphc0 & LOWPAN_IPHC_NH_C)
903 if (lowpan_uncompress_udp_header(skb))
904 goto drop;
663 905
664 /* Not fragmented package */ 906 /* Not fragmented package */
665 hdr.payload_len = htons(skb->len); 907 hdr.payload_len = htons(skb->len);
@@ -674,6 +916,9 @@ lowpan_process_data(struct sk_buff *skb)
674 lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, 916 lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
675 sizeof(hdr)); 917 sizeof(hdr));
676 return lowpan_skb_deliver(skb, &hdr); 918 return lowpan_skb_deliver(skb, &hdr);
919
920unlock_and_drop:
921 spin_unlock(&flist_lock);
677drop: 922drop:
678 kfree_skb(skb); 923 kfree_skb(skb);
679 return -EINVAL; 924 return -EINVAL;
@@ -692,18 +937,115 @@ static int lowpan_set_address(struct net_device *dev, void *p)
692 return 0; 937 return 0;
693} 938}
694 939
940static int lowpan_get_mac_header_length(struct sk_buff *skb)
941{
942 /*
943 * Currently long addressing mode is supported only, so the overall
944 * header size is 21:
945 * FC SeqNum DPAN DA SA Sec
946 * 2 + 1 + 2 + 8 + 8 + 0 = 21
947 */
948 return 21;
949}
950
951static int
952lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
953 int mlen, int plen, int offset)
954{
955 struct sk_buff *frag;
956 int hlen, ret;
957
958 /* if payload length is zero, therefore it's a first fragment */
959 hlen = (plen == 0 ? LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE);
960
961 lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
962
963 frag = dev_alloc_skb(hlen + mlen + plen + IEEE802154_MFR_SIZE);
964 if (!frag)
965 return -ENOMEM;
966
967 frag->priority = skb->priority;
968 frag->dev = skb->dev;
969
970 /* copy header, MFR and payload */
971 memcpy(skb_put(frag, mlen), skb->data, mlen);
972 memcpy(skb_put(frag, hlen), head, hlen);
973
974 if (plen)
975 skb_copy_from_linear_data_offset(skb, offset + mlen,
976 skb_put(frag, plen), plen);
977
978 lowpan_raw_dump_table(__func__, " raw fragment dump", frag->data,
979 frag->len);
980
981 ret = dev_queue_xmit(frag);
982
983 return ret;
984}
985
986static int
987lowpan_skb_fragmentation(struct sk_buff *skb)
988{
989 int err, header_length, payload_length, tag, offset = 0;
990 u8 head[5];
991
992 header_length = lowpan_get_mac_header_length(skb);
993 payload_length = skb->len - header_length;
994 tag = fragment_tag++;
995
996 /* first fragment header */
997 head[0] = LOWPAN_DISPATCH_FRAG1 | (payload_length & 0x7);
998 head[1] = (payload_length >> 3) & 0xff;
999 head[2] = tag & 0xff;
1000 head[3] = tag >> 8;
1001
1002 err = lowpan_fragment_xmit(skb, head, header_length, 0, 0);
1003
1004 /* next fragment header */
1005 head[0] &= ~LOWPAN_DISPATCH_FRAG1;
1006 head[0] |= LOWPAN_DISPATCH_FRAGN;
1007
1008 while ((payload_length - offset > 0) && (err >= 0)) {
1009 int len = LOWPAN_FRAG_SIZE;
1010
1011 head[4] = offset / 8;
1012
1013 if (payload_length - offset < len)
1014 len = payload_length - offset;
1015
1016 err = lowpan_fragment_xmit(skb, head, header_length,
1017 len, offset);
1018 offset += len;
1019 }
1020
1021 return err;
1022}
1023
695static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) 1024static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
696{ 1025{
697 int err = 0; 1026 int err = -1;
698 1027
699 pr_debug("(%s): package xmit\n", __func__); 1028 pr_debug("(%s): package xmit\n", __func__);
700 1029
701 skb->dev = lowpan_dev_info(dev)->real_dev; 1030 skb->dev = lowpan_dev_info(dev)->real_dev;
702 if (skb->dev == NULL) { 1031 if (skb->dev == NULL) {
703 pr_debug("(%s) ERROR: no real wpan device found\n", __func__); 1032 pr_debug("(%s) ERROR: no real wpan device found\n", __func__);
704 dev_kfree_skb(skb); 1033 goto error;
705 } else 1034 }
1035
1036 if (skb->len <= IEEE802154_MTU) {
706 err = dev_queue_xmit(skb); 1037 err = dev_queue_xmit(skb);
1038 goto out;
1039 }
1040
1041 pr_debug("(%s): frame is too big, fragmentation is needed\n",
1042 __func__);
1043 err = lowpan_skb_fragmentation(skb);
1044error:
1045 dev_kfree_skb(skb);
1046out:
1047 if (err < 0)
1048 pr_debug("(%s): ERROR: xmit failed\n", __func__);
707 1049
708 return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK); 1050 return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
709} 1051}
@@ -730,13 +1072,12 @@ static void lowpan_setup(struct net_device *dev)
730 dev->addr_len = IEEE802154_ADDR_LEN; 1072 dev->addr_len = IEEE802154_ADDR_LEN;
731 memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); 1073 memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
732 dev->type = ARPHRD_IEEE802154; 1074 dev->type = ARPHRD_IEEE802154;
733 dev->features = NETIF_F_NO_CSUM;
734 /* Frame Control + Sequence Number + Address fields + Security Header */ 1075 /* Frame Control + Sequence Number + Address fields + Security Header */
735 dev->hard_header_len = 2 + 1 + 20 + 14; 1076 dev->hard_header_len = 2 + 1 + 20 + 14;
736 dev->needed_tailroom = 2; /* FCS */ 1077 dev->needed_tailroom = 2; /* FCS */
737 dev->mtu = 1281; 1078 dev->mtu = 1281;
738 dev->tx_queue_len = 0; 1079 dev->tx_queue_len = 0;
739 dev->flags = IFF_NOARP | IFF_BROADCAST; 1080 dev->flags = IFF_BROADCAST | IFF_MULTICAST;
740 dev->watchdog_timeo = 0; 1081 dev->watchdog_timeo = 0;
741 1082
742 dev->netdev_ops = &lowpan_netdev_ops; 1083 dev->netdev_ops = &lowpan_netdev_ops;
@@ -765,8 +1106,15 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
765 goto drop; 1106 goto drop;
766 1107
767 /* check that it's our buffer */ 1108 /* check that it's our buffer */
768 if ((skb->data[0] & 0xe0) == 0x60) 1109 switch (skb->data[0] & 0xe0) {
1110 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
1111 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
1112 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
769 lowpan_process_data(skb); 1113 lowpan_process_data(skb);
1114 break;
1115 default:
1116 break;
1117 }
770 1118
771 return NET_RX_SUCCESS; 1119 return NET_RX_SUCCESS;
772 1120