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_devices(struct sk_buff *skb,
19 struct net_device *dev)
21 struct lowpan_dev_record *entry;
22 struct sk_buff *skb_cp;
23 int stat = NET_RX_SUCCESS;
25 skb->protocol = htons(ETH_P_IPV6);
26 skb->pkt_type = PACKET_HOST;
29 list_for_each_entry_rcu(entry, &lowpan_devices, list)
30 if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
31 skb_cp = skb_copy(skb, GFP_ATOMIC);
38 skb_cp->dev = entry->ldev;
39 stat = netif_rx(skb_cp);
40 if (stat == NET_RX_DROP)
51 iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
54 struct ieee802154_addr_sa sa, da;
57 raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
58 /* at least two bytes will be used for the encoding */
62 if (lowpan_fetch_skb_u8(skb, &iphc0))
65 if (lowpan_fetch_skb_u8(skb, &iphc1))
68 ieee802154_addr_to_sa(&sa, &hdr->source);
69 ieee802154_addr_to_sa(&da, &hdr->dest);
71 if (sa.addr_type == IEEE802154_ADDR_SHORT)
76 if (da.addr_type == IEEE802154_ADDR_SHORT)
81 return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
82 IEEE802154_ADDR_LEN, dap, da.addr_type,
83 IEEE802154_ADDR_LEN, iphc0, iphc1);
86 static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
87 struct packet_type *pt, struct net_device *orig_dev)
89 struct ieee802154_hdr hdr;
92 skb = skb_share_check(skb, GFP_ATOMIC);
96 if (!netif_running(dev))
99 if (skb->pkt_type == PACKET_OTHERHOST)
102 if (dev->type != ARPHRD_IEEE802154)
105 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
108 /* check that it's our buffer */
109 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
110 /* Pull off the 1-byte of 6lowpan header. */
112 return lowpan_give_skb_to_devices(skb, NULL);
114 switch (skb->data[0] & 0xe0) {
115 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
116 ret = iphc_decompress(skb, &hdr);
120 return lowpan_give_skb_to_devices(skb, NULL);
121 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
122 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
124 ret = iphc_decompress(skb, &hdr);
128 return lowpan_give_skb_to_devices(skb, NULL);
129 } else if (ret == -1) {
132 return NET_RX_SUCCESS;
134 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
135 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
137 ret = iphc_decompress(skb, &hdr);
141 return lowpan_give_skb_to_devices(skb, NULL);
142 } else if (ret == -1) {
145 return NET_RX_SUCCESS;
158 static struct packet_type lowpan_packet_type = {
159 .type = htons(ETH_P_IEEE802154),
163 void lowpan_rx_init(void)
165 dev_add_pack(&lowpan_packet_type);
168 void lowpan_rx_exit(void)
170 dev_remove_pack(&lowpan_packet_type);