diff options
author | Alan Ott <alan@signal11.us> | 2013-01-16 19:09:48 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-18 14:18:30 -0500 |
commit | ee21c7e0d1f6e742e9f441f580a3bac316a39a21 (patch) | |
tree | 36baeee5552a9256ee607d35eb4e21221f537adc /net/ieee802154 | |
parent | 0c446212c4f68e51ba03a9b172599437d6660a9d (diff) | |
download | linux-ee21c7e0d1f6e742e9f441f580a3bac316a39a21.tar.gz linux-ee21c7e0d1f6e742e9f441f580a3bac316a39a21.tar.bz2 linux-ee21c7e0d1f6e742e9f441f580a3bac316a39a21.zip |
6lowpan: Handle uncompressed IPv6 packets over 6LoWPAN
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>
Diffstat (limited to 'net/ieee802154')
-rw-r--r-- | net/ieee802154/6lowpan.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 1714cfab1220..09cba81d2c4a 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -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; |