blob: 74d8fec51a0c45a37159762eb51256f688bd5acb [file] [log] [blame]
Alexander Aring4662a0d2015-01-04 17:10:55 +01001/* 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.
4 *
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.
9 */
10
11#include <linux/if_arp.h>
12
13#include <net/6lowpan.h>
14#include <net/ieee802154_netdev.h>
15
16#include "6lowpan_i.h"
17
Alexander Aring51e0e5d2015-08-10 21:15:53 +020018static int lowpan_give_skb_to_device(struct sk_buff *skb,
Alexander Aringf4606582015-09-02 14:21:16 +020019 struct net_device *wdev)
Alexander Aring4662a0d2015-01-04 17:10:55 +010020{
Alexander Aringf4606582015-09-02 14:21:16 +020021 skb->dev = wdev->ieee802154_ptr->lowpan_dev;
Alexander Aring4662a0d2015-01-04 17:10:55 +010022 skb->protocol = htons(ETH_P_IPV6);
23 skb->pkt_type = PACKET_HOST;
24
Alexander Aring51e0e5d2015-08-10 21:15:53 +020025 return netif_rx(skb);
Alexander Aring4662a0d2015-01-04 17:10:55 +010026}
27
28static int
29iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
30{
31 u8 iphc0, iphc1;
32 struct ieee802154_addr_sa sa, da;
33 void *sap, *dap;
34
35 raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
Alexander Aring4662a0d2015-01-04 17:10:55 +010036
Alexander Aringad23d5b2015-09-02 14:21:22 +020037 if (lowpan_fetch_skb_u8(skb, &iphc0) ||
38 lowpan_fetch_skb_u8(skb, &iphc1))
Alexander Aring4662a0d2015-01-04 17:10:55 +010039 return -EINVAL;
40
41 ieee802154_addr_to_sa(&sa, &hdr->source);
42 ieee802154_addr_to_sa(&da, &hdr->dest);
43
44 if (sa.addr_type == IEEE802154_ADDR_SHORT)
45 sap = &sa.short_addr;
46 else
47 sap = &sa.hwaddr;
48
49 if (da.addr_type == IEEE802154_ADDR_SHORT)
50 dap = &da.short_addr;
51 else
52 dap = &da.hwaddr;
53
54 return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
55 IEEE802154_ADDR_LEN, dap, da.addr_type,
56 IEEE802154_ADDR_LEN, iphc0, iphc1);
57}
58
Alexander Aringf4606582015-09-02 14:21:16 +020059static int lowpan_rcv(struct sk_buff *skb, struct net_device *wdev,
60 struct packet_type *pt, struct net_device *orig_wdev)
Alexander Aring4662a0d2015-01-04 17:10:55 +010061{
62 struct ieee802154_hdr hdr;
Alexander Aring989d4332015-09-02 14:21:21 +020063 struct net_device *ldev;
Alexander Aring4662a0d2015-01-04 17:10:55 +010064 int ret;
65
Alexander Aring742c3af2015-09-02 14:21:23 +020066 if (wdev->type != ARPHRD_IEEE802154 ||
67 skb->pkt_type == PACKET_OTHERHOST)
Alexander Aring989d4332015-09-02 14:21:21 +020068 goto drop;
69
70 ldev = wdev->ieee802154_ptr->lowpan_dev;
71 if (!ldev || !netif_running(ldev))
Alexander Aringc0015bf2015-08-15 11:00:33 +020072 goto drop;
73
Alexander Aring4662a0d2015-01-04 17:10:55 +010074 skb = skb_share_check(skb, GFP_ATOMIC);
75 if (!skb)
76 goto drop;
77
Alexander Aring4662a0d2015-01-04 17:10:55 +010078 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
79 goto drop_skb;
80
81 /* check that it's our buffer */
82 if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
83 /* Pull off the 1-byte of 6lowpan header. */
84 skb_pull(skb, 1);
Alexander Aringf4606582015-09-02 14:21:16 +020085 return lowpan_give_skb_to_device(skb, wdev);
Alexander Aring4662a0d2015-01-04 17:10:55 +010086 } else {
87 switch (skb->data[0] & 0xe0) {
88 case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
89 ret = iphc_decompress(skb, &hdr);
90 if (ret < 0)
91 goto drop_skb;
92
Alexander Aringf4606582015-09-02 14:21:16 +020093 return lowpan_give_skb_to_device(skb, wdev);
Alexander Aring4662a0d2015-01-04 17:10:55 +010094 case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
95 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
96 if (ret == 1) {
97 ret = iphc_decompress(skb, &hdr);
98 if (ret < 0)
99 goto drop_skb;
100
Alexander Aringf4606582015-09-02 14:21:16 +0200101 return lowpan_give_skb_to_device(skb, wdev);
Alexander Aring4662a0d2015-01-04 17:10:55 +0100102 } else if (ret == -1) {
103 return NET_RX_DROP;
104 } else {
105 return NET_RX_SUCCESS;
106 }
107 case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
108 ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
109 if (ret == 1) {
110 ret = iphc_decompress(skb, &hdr);
111 if (ret < 0)
112 goto drop_skb;
113
Alexander Aringf4606582015-09-02 14:21:16 +0200114 return lowpan_give_skb_to_device(skb, wdev);
Alexander Aring4662a0d2015-01-04 17:10:55 +0100115 } else if (ret == -1) {
116 return NET_RX_DROP;
117 } else {
118 return NET_RX_SUCCESS;
119 }
120 default:
121 break;
122 }
123 }
124
125drop_skb:
126 kfree_skb(skb);
127drop:
128 return NET_RX_DROP;
129}
130
131static struct packet_type lowpan_packet_type = {
132 .type = htons(ETH_P_IEEE802154),
133 .func = lowpan_rcv,
134};
135
136void lowpan_rx_init(void)
137{
138 dev_add_pack(&lowpan_packet_type);
139}
140
141void lowpan_rx_exit(void)
142{
143 dev_remove_pack(&lowpan_packet_type);
144}