6lowpan: Handle uncompressed IPv6 packets over 6LoWPAN
authorAlan Ott <alan@signal11.us>
Wed, 16 Jan 2013 19:09:48 +0000 (19:09 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Jan 2013 19:18:30 +0000 (14:18 -0500)
Handle the reception of uncompressed packets (dispatch type = IPv6).

Signed-off-by: Alan Ott <alan@signal11.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ieee802154/6lowpan.c

index 1714cfab12204c04107e2201749bda42077f43e9..09cba81d2c4ab65f18963a34f9a7857fc4860367 100644 (file)
@@ -1147,19 +1147,42 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                goto drop;
 
        /* check that it's our buffer */
-       switch (skb->data[0] & 0xe0) {
-       case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
-       case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
-       case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
-               local_skb = skb_clone(skb, GFP_ATOMIC);
+       if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+               /* Copy the packet so that the IPv6 header is
+                * properly aligned.
+                */
+               local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
+                                           skb_tailroom(skb), GFP_ATOMIC);
                if (!local_skb)
                        goto drop;
-               lowpan_process_data(local_skb);
 
+               local_skb->protocol = htons(ETH_P_IPV6);
+               local_skb->pkt_type = PACKET_HOST;
+
+               /* Pull off the 1-byte of 6lowpan header. */
+               skb_pull(local_skb, 1);
+               skb_reset_network_header(local_skb);
+               skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
+
+               lowpan_give_skb_to_devices(local_skb);
+
+               kfree_skb(local_skb);
                kfree_skb(skb);
-               break;
-       default:
-               break;
+       } else {
+               switch (skb->data[0] & 0xe0) {
+               case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+               case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
+               case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
+                       local_skb = skb_clone(skb, GFP_ATOMIC);
+                       if (!local_skb)
+                               goto drop;
+                       lowpan_process_data(local_skb);
+
+                       kfree_skb(skb);
+                       break;
+               default:
+                       break;
+               }
        }
 
        return NET_RX_SUCCESS;