diff options
Diffstat (limited to 'net/ieee802154/6lowpan.c')
-rw-r--r-- | net/ieee802154/6lowpan.c | 94 |
1 files changed, 61 insertions, 33 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index f651da60f161..43b95ca61114 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c | |||
@@ -377,17 +377,14 @@ static int lowpan_header_create(struct sk_buff *skb, | |||
377 | struct ipv6hdr *hdr; | 377 | struct ipv6hdr *hdr; |
378 | const u8 *saddr = _saddr; | 378 | const u8 *saddr = _saddr; |
379 | const u8 *daddr = _daddr; | 379 | const u8 *daddr = _daddr; |
380 | u8 *head; | 380 | u8 head[100]; |
381 | struct ieee802154_addr sa, da; | 381 | struct ieee802154_addr sa, da; |
382 | 382 | ||
383 | /* TODO: | ||
384 | * if this package isn't ipv6 one, where should it be routed? | ||
385 | */ | ||
383 | if (type != ETH_P_IPV6) | 386 | if (type != ETH_P_IPV6) |
384 | return 0; | 387 | return 0; |
385 | /* TODO: | ||
386 | * if this package isn't ipv6 one, where should it be routed? | ||
387 | */ | ||
388 | head = kzalloc(100, GFP_KERNEL); | ||
389 | if (head == NULL) | ||
390 | return -ENOMEM; | ||
391 | 388 | ||
392 | hdr = ipv6_hdr(skb); | 389 | hdr = ipv6_hdr(skb); |
393 | hc06_ptr = head + 2; | 390 | hc06_ptr = head + 2; |
@@ -561,8 +558,6 @@ static int lowpan_header_create(struct sk_buff *skb, | |||
561 | skb_pull(skb, sizeof(struct ipv6hdr)); | 558 | skb_pull(skb, sizeof(struct ipv6hdr)); |
562 | memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); | 559 | memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); |
563 | 560 | ||
564 | kfree(head); | ||
565 | |||
566 | lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, | 561 | lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, |
567 | skb->len); | 562 | skb->len); |
568 | 563 | ||
@@ -594,10 +589,32 @@ static int lowpan_header_create(struct sk_buff *skb, | |||
594 | } | 589 | } |
595 | } | 590 | } |
596 | 591 | ||
592 | static int lowpan_give_skb_to_devices(struct sk_buff *skb) | ||
593 | { | ||
594 | struct lowpan_dev_record *entry; | ||
595 | struct sk_buff *skb_cp; | ||
596 | int stat = NET_RX_SUCCESS; | ||
597 | |||
598 | rcu_read_lock(); | ||
599 | list_for_each_entry_rcu(entry, &lowpan_devices, list) | ||
600 | if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) { | ||
601 | skb_cp = skb_copy(skb, GFP_ATOMIC); | ||
602 | if (!skb_cp) { | ||
603 | stat = -ENOMEM; | ||
604 | break; | ||
605 | } | ||
606 | |||
607 | skb_cp->dev = entry->ldev; | ||
608 | stat = netif_rx(skb_cp); | ||
609 | } | ||
610 | rcu_read_unlock(); | ||
611 | |||
612 | return stat; | ||
613 | } | ||
614 | |||
597 | static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) | 615 | static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) |
598 | { | 616 | { |
599 | struct sk_buff *new; | 617 | struct sk_buff *new; |
600 | struct lowpan_dev_record *entry; | ||
601 | int stat = NET_RX_SUCCESS; | 618 | int stat = NET_RX_SUCCESS; |
602 | 619 | ||
603 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), | 620 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), |
@@ -614,19 +631,7 @@ static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) | |||
614 | new->protocol = htons(ETH_P_IPV6); | 631 | new->protocol = htons(ETH_P_IPV6); |
615 | new->pkt_type = PACKET_HOST; | 632 | new->pkt_type = PACKET_HOST; |
616 | 633 | ||
617 | rcu_read_lock(); | 634 | stat = lowpan_give_skb_to_devices(new); |
618 | list_for_each_entry_rcu(entry, &lowpan_devices, list) | ||
619 | if (lowpan_dev_info(entry->ldev)->real_dev == new->dev) { | ||
620 | skb = skb_copy(new, GFP_ATOMIC); | ||
621 | if (!skb) { | ||
622 | stat = -ENOMEM; | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | skb->dev = entry->ldev; | ||
627 | stat = netif_rx(skb); | ||
628 | } | ||
629 | rcu_read_unlock(); | ||
630 | 635 | ||
631 | kfree_skb(new); | 636 | kfree_skb(new); |
632 | 637 | ||
@@ -1137,19 +1142,42 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | |||
1137 | goto drop; | 1142 | goto drop; |
1138 | 1143 | ||
1139 | /* check that it's our buffer */ | 1144 | /* check that it's our buffer */ |
1140 | switch (skb->data[0] & 0xe0) { | 1145 | if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { |
1141 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ | 1146 | /* Copy the packet so that the IPv6 header is |
1142 | case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ | 1147 | * properly aligned. |
1143 | case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ | 1148 | */ |
1144 | local_skb = skb_clone(skb, GFP_ATOMIC); | 1149 | local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1, |
1150 | skb_tailroom(skb), GFP_ATOMIC); | ||
1145 | if (!local_skb) | 1151 | if (!local_skb) |
1146 | goto drop; | 1152 | goto drop; |
1147 | lowpan_process_data(local_skb); | ||
1148 | 1153 | ||
1154 | local_skb->protocol = htons(ETH_P_IPV6); | ||
1155 | local_skb->pkt_type = PACKET_HOST; | ||
1156 | |||
1157 | /* Pull off the 1-byte of 6lowpan header. */ | ||
1158 | skb_pull(local_skb, 1); | ||
1159 | skb_reset_network_header(local_skb); | ||
1160 | skb_set_transport_header(local_skb, sizeof(struct ipv6hdr)); | ||
1161 | |||
1162 | lowpan_give_skb_to_devices(local_skb); | ||
1163 | |||
1164 | kfree_skb(local_skb); | ||
1149 | kfree_skb(skb); | 1165 | kfree_skb(skb); |
1150 | break; | 1166 | } else { |
1151 | default: | 1167 | switch (skb->data[0] & 0xe0) { |
1152 | break; | 1168 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ |
1169 | case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ | ||
1170 | case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ | ||
1171 | local_skb = skb_clone(skb, GFP_ATOMIC); | ||
1172 | if (!local_skb) | ||
1173 | goto drop; | ||
1174 | lowpan_process_data(local_skb); | ||
1175 | |||
1176 | kfree_skb(skb); | ||
1177 | break; | ||
1178 | default: | ||
1179 | break; | ||
1180 | } | ||
1153 | } | 1181 | } |
1154 | 1182 | ||
1155 | return NET_RX_SUCCESS; | 1183 | return NET_RX_SUCCESS; |
@@ -1234,7 +1262,7 @@ static inline int __init lowpan_netlink_init(void) | |||
1234 | return rtnl_link_register(&lowpan_link_ops); | 1262 | return rtnl_link_register(&lowpan_link_ops); |
1235 | } | 1263 | } |
1236 | 1264 | ||
1237 | static inline void __init lowpan_netlink_fini(void) | 1265 | static inline void lowpan_netlink_fini(void) |
1238 | { | 1266 | { |
1239 | rtnl_link_unregister(&lowpan_link_ops); | 1267 | rtnl_link_unregister(&lowpan_link_ops); |
1240 | } | 1268 | } |