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.c94
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
592static 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
597static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr) 615static 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
1237static inline void __init lowpan_netlink_fini(void) 1265static inline void lowpan_netlink_fini(void)
1238{ 1266{
1239 rtnl_link_unregister(&lowpan_link_ops); 1267 rtnl_link_unregister(&lowpan_link_ops);
1240} 1268}