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.
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/mac802154.h>
15#include <net/ieee802154_netdev.h>
16
17#include "6lowpan_i.h"
18
19#define LOWPAN_DISPATCH_FIRST		0xc0
20#define LOWPAN_DISPATCH_FRAG_MASK	0xf8
21
22#define LOWPAN_DISPATCH_NALP		0x00
23#define LOWPAN_DISPATCH_ESC		0x40
24#define LOWPAN_DISPATCH_HC1		0x42
25#define LOWPAN_DISPATCH_DFF		0x43
26#define LOWPAN_DISPATCH_BC0		0x50
27#define LOWPAN_DISPATCH_MESH		0x80
28
29static int lowpan_give_skb_to_device(struct sk_buff *skb)
30{
31	skb->protocol = htons(ETH_P_IPV6);
32	skb->dev->stats.rx_packets++;
33	skb->dev->stats.rx_bytes += skb->len;
34
35	return netif_rx(skb);
36}
37
38static int lowpan_rx_handlers_result(struct sk_buff *skb, lowpan_rx_result res)
39{
40	switch (res) {
41	case RX_CONTINUE:
42		/* nobody cared about this packet */
43		net_warn_ratelimited("%s: received unknown dispatch\n",
44				     __func__);
45
46		/* fall-through */
47	case RX_DROP_UNUSABLE:
48		kfree_skb(skb);
49
50		/* fall-through */
51	case RX_DROP:
52		return NET_RX_DROP;
53	case RX_QUEUED:
54		return lowpan_give_skb_to_device(skb);
55	default:
56		break;
57	}
58
59	return NET_RX_DROP;
60}
61
62static inline bool lowpan_is_frag1(u8 dispatch)
63{
64	return (dispatch & LOWPAN_DISPATCH_FRAG_MASK) == LOWPAN_DISPATCH_FRAG1;
65}
66
67static inline bool lowpan_is_fragn(u8 dispatch)
68{
69	return (dispatch & LOWPAN_DISPATCH_FRAG_MASK) == LOWPAN_DISPATCH_FRAGN;
70}
71
72static lowpan_rx_result lowpan_rx_h_frag(struct sk_buff *skb)
73{
74	int ret;
75
76	if (!(lowpan_is_frag1(*skb_network_header(skb)) ||
77	      lowpan_is_fragn(*skb_network_header(skb))))
78		return RX_CONTINUE;
79
80	ret = lowpan_frag_rcv(skb, *skb_network_header(skb) &
81			      LOWPAN_DISPATCH_FRAG_MASK);
82	if (ret == 1)
83		return RX_QUEUED;
84
85	/* Packet is freed by lowpan_frag_rcv on error or put into the frag
86	 * bucket.
87	 */
88	return RX_DROP;
89}
90
91int lowpan_iphc_decompress(struct sk_buff *skb)
92{
93	struct ieee802154_hdr hdr;
94
95	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
96		return -EINVAL;
97
98	return lowpan_header_decompress(skb, skb->dev, &hdr.dest, &hdr.source);
99}
100
101static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)
102{
103	int ret;
104
105	if (!lowpan_is_iphc(*skb_network_header(skb)))
106		return RX_CONTINUE;
107
108	/* Setting datagram_offset to zero indicates non frag handling
109	 * while doing lowpan_header_decompress.
110	 */
111	lowpan_802154_cb(skb)->d_size = 0;
112
113	ret = lowpan_iphc_decompress(skb);
114	if (ret < 0)
115		return RX_DROP_UNUSABLE;
116
117	return RX_QUEUED;
118}
119
120lowpan_rx_result lowpan_rx_h_ipv6(struct sk_buff *skb)
121{
122	if (!lowpan_is_ipv6(*skb_network_header(skb)))
123		return RX_CONTINUE;
124
125	/* Pull off the 1-byte of 6lowpan header. */
126	skb_pull(skb, 1);
127	return RX_QUEUED;
128}
129
130static inline bool lowpan_is_esc(u8 dispatch)
131{
132	return dispatch == LOWPAN_DISPATCH_ESC;
133}
134
135static lowpan_rx_result lowpan_rx_h_esc(struct sk_buff *skb)
136{
137	if (!lowpan_is_esc(*skb_network_header(skb)))
138		return RX_CONTINUE;
139
140	net_warn_ratelimited("%s: %s\n", skb->dev->name,
141			     "6LoWPAN ESC not supported\n");
142
143	return RX_DROP_UNUSABLE;
144}
145
146static inline bool lowpan_is_hc1(u8 dispatch)
147{
148	return dispatch == LOWPAN_DISPATCH_HC1;
149}
150
151static lowpan_rx_result lowpan_rx_h_hc1(struct sk_buff *skb)
152{
153	if (!lowpan_is_hc1(*skb_network_header(skb)))
154		return RX_CONTINUE;
155
156	net_warn_ratelimited("%s: %s\n", skb->dev->name,
157			     "6LoWPAN HC1 not supported\n");
158
159	return RX_DROP_UNUSABLE;
160}
161
162static inline bool lowpan_is_dff(u8 dispatch)
163{
164	return dispatch == LOWPAN_DISPATCH_DFF;
165}
166
167static lowpan_rx_result lowpan_rx_h_dff(struct sk_buff *skb)
168{
169	if (!lowpan_is_dff(*skb_network_header(skb)))
170		return RX_CONTINUE;
171
172	net_warn_ratelimited("%s: %s\n", skb->dev->name,
173			     "6LoWPAN DFF not supported\n");
174
175	return RX_DROP_UNUSABLE;
176}
177
178static inline bool lowpan_is_bc0(u8 dispatch)
179{
180	return dispatch == LOWPAN_DISPATCH_BC0;
181}
182
183static lowpan_rx_result lowpan_rx_h_bc0(struct sk_buff *skb)
184{
185	if (!lowpan_is_bc0(*skb_network_header(skb)))
186		return RX_CONTINUE;
187
188	net_warn_ratelimited("%s: %s\n", skb->dev->name,
189			     "6LoWPAN BC0 not supported\n");
190
191	return RX_DROP_UNUSABLE;
192}
193
194static inline bool lowpan_is_mesh(u8 dispatch)
195{
196	return (dispatch & LOWPAN_DISPATCH_FIRST) == LOWPAN_DISPATCH_MESH;
197}
198
199static lowpan_rx_result lowpan_rx_h_mesh(struct sk_buff *skb)
200{
201	if (!lowpan_is_mesh(*skb_network_header(skb)))
202		return RX_CONTINUE;
203
204	net_warn_ratelimited("%s: %s\n", skb->dev->name,
205			     "6LoWPAN MESH not supported\n");
206
207	return RX_DROP_UNUSABLE;
208}
209
210static int lowpan_invoke_rx_handlers(struct sk_buff *skb)
211{
212	lowpan_rx_result res;
213
214#define CALL_RXH(rxh)			\
215	do {				\
216		res = rxh(skb);	\
217		if (res != RX_CONTINUE)	\
218			goto rxh_next;	\
219	} while (0)
220
221	/* likely at first */
222	CALL_RXH(lowpan_rx_h_iphc);
223	CALL_RXH(lowpan_rx_h_frag);
224	CALL_RXH(lowpan_rx_h_ipv6);
225	CALL_RXH(lowpan_rx_h_esc);
226	CALL_RXH(lowpan_rx_h_hc1);
227	CALL_RXH(lowpan_rx_h_dff);
228	CALL_RXH(lowpan_rx_h_bc0);
229	CALL_RXH(lowpan_rx_h_mesh);
230
231rxh_next:
232	return lowpan_rx_handlers_result(skb, res);
233#undef CALL_RXH
234}
235
236static inline bool lowpan_is_nalp(u8 dispatch)
237{
238	return (dispatch & LOWPAN_DISPATCH_FIRST) == LOWPAN_DISPATCH_NALP;
239}
240
241/* Lookup for reserved dispatch values at:
242 * https://www.iana.org/assignments/_6lowpan-parameters/_6lowpan-parameters.xhtml#_6lowpan-parameters-1
243 *
244 * Last Updated: 2015-01-22
245 */
246static inline bool lowpan_is_reserved(u8 dispatch)
247{
248	return ((dispatch >= 0x44 && dispatch <= 0x4F) ||
249		(dispatch >= 0x51 && dispatch <= 0x5F) ||
250		(dispatch >= 0xc8 && dispatch <= 0xdf) ||
251		(dispatch >= 0xe8 && dispatch <= 0xff));
252}
253
254/* lowpan_rx_h_check checks on generic 6LoWPAN requirements
255 * in MAC and 6LoWPAN header.
256 *
257 * Don't manipulate the skb here, it could be shared buffer.
258 */
259static inline bool lowpan_rx_h_check(struct sk_buff *skb)
260{
261	__le16 fc = ieee802154_get_fc_from_skb(skb);
262
263	/* check on ieee802154 conform 6LoWPAN header */
264	if (!ieee802154_is_data(fc) ||
265	    !ieee802154_is_intra_pan(fc))
266		return false;
267
268	/* check if we can dereference the dispatch */
269	if (unlikely(!skb->len))
270		return false;
271
272	if (lowpan_is_nalp(*skb_network_header(skb)) ||
273	    lowpan_is_reserved(*skb_network_header(skb)))
274		return false;
275
276	return true;
277}
278
279static int lowpan_rcv(struct sk_buff *skb, struct net_device *wdev,
280		      struct packet_type *pt, struct net_device *orig_wdev)
281{
282	struct net_device *ldev;
283
284	if (wdev->type != ARPHRD_IEEE802154 ||
285	    skb->pkt_type == PACKET_OTHERHOST ||
286	    !lowpan_rx_h_check(skb))
287		goto drop;
288
289	ldev = wdev->ieee802154_ptr->lowpan_dev;
290	if (!ldev || !netif_running(ldev))
291		goto drop;
292
293	/* Replacing skb->dev and followed rx handlers will manipulate skb. */
294	skb = skb_share_check(skb, GFP_ATOMIC);
295	if (!skb)
296		goto out;
297	skb->dev = ldev;
298
299	/* When receive frag1 it's likely that we manipulate the buffer.
300	 * When recevie iphc we manipulate the data buffer. So we need
301	 * to unshare the buffer.
302	 */
303	if (lowpan_is_frag1(*skb_network_header(skb)) ||
304	    lowpan_is_iphc(*skb_network_header(skb))) {
305		skb = skb_unshare(skb, GFP_ATOMIC);
306		if (!skb)
307			goto out;
308	}
309
310	return lowpan_invoke_rx_handlers(skb);
311
312drop:
313	kfree_skb(skb);
314out:
315	return NET_RX_DROP;
316}
317
318static struct packet_type lowpan_packet_type = {
319	.type = htons(ETH_P_IEEE802154),
320	.func = lowpan_rcv,
321};
322
323void lowpan_rx_init(void)
324{
325	dev_add_pack(&lowpan_packet_type);
326}
327
328void lowpan_rx_exit(void)
329{
330	dev_remove_pack(&lowpan_packet_type);
331}
332