1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License version 2
3 * as published by the Free Software Foundation.
5 * This program is distributed in the hope that it will be useful,
6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 * GNU General Public License for more details.
11 #include <linux/if_arp.h>
13 #include <net/6lowpan.h>
14 #include <net/ieee802154_netdev.h>
16 #include "6lowpan_i.h"
18 static int lowpan_give_skb_to_device(struct sk_buff *skb,
19 struct net_device *dev)
21 skb->dev = dev->ieee802154_ptr->lowpan_dev;
22 skb->protocol = htons(ETH_P_IPV6);
23 skb->pkt_type = PACKET_HOST;
29 iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
32 struct ieee802154_addr_sa sa, da;
35 raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
36 /* at least two bytes will be used for the encoding */
40 if (lowpan_fetch_skb_u8(skb, &iphc0))
43 if (lowpan_fetch_skb_u8(skb, &iphc1))
46 ieee802154_addr_to_sa(&sa, &hdr->source);
47 ieee802154_addr_to_sa(&da, &hdr->dest);
49 if (sa.addr_type == IEEE802154_ADDR_SHORT)
54 if (da.addr_type == IEEE802154_ADDR_SHORT)
59 return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
60 IEEE802154_ADDR_LEN, dap, da.addr_type,
61 IEEE802154_ADDR_LEN, iphc0, iphc1);
64 static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
65 struct packet_type *pt, struct net_device *orig_dev)
67 struct ieee802154_hdr hdr;
70 if (dev->type != ARPHRD_IEEE802154 ||
71 !dev->ieee802154_ptr->lowpan_dev)
74 skb = skb_share_check(skb, GFP_ATOMIC);
78 if (!netif_running(dev))
81 if (skb->pkt_type == PACKET_OTHERHOST)
84 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
87 /* check that it's our buffer */
88 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
89 /* Pull off the 1-byte of 6lowpan header. */
91 return lowpan_give_skb_to_device(skb, dev);
93 switch (skb->data[0] & 0xe0) {
94 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
95 ret = iphc_decompress(skb, &hdr);
99 return lowpan_give_skb_to_device(skb, dev);
100 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
101 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
103 ret = iphc_decompress(skb, &hdr);
107 return lowpan_give_skb_to_device(skb, dev);
108 } else if (ret == -1) {
111 return NET_RX_SUCCESS;
113 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
114 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
116 ret = iphc_decompress(skb, &hdr);
120 return lowpan_give_skb_to_device(skb, dev);
121 } else if (ret == -1) {
124 return NET_RX_SUCCESS;
137 static struct packet_type lowpan_packet_type = {
138 .type = htons(ETH_P_IEEE802154),
142 void lowpan_rx_init(void)
144 dev_add_pack(&lowpan_packet_type);
147 void lowpan_rx_exit(void)
149 dev_remove_pack(&lowpan_packet_type);