xref: /openbmc/linux/net/ieee802154/6lowpan/rx.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24662a0daSAlexander Aring 
34662a0daSAlexander Aring #include <linux/if_arp.h>
44662a0daSAlexander Aring 
54662a0daSAlexander Aring #include <net/6lowpan.h>
654552d03SAlexander Aring #include <net/mac802154.h>
74662a0daSAlexander Aring #include <net/ieee802154_netdev.h>
84662a0daSAlexander Aring 
94662a0daSAlexander Aring #include "6lowpan_i.h"
104662a0daSAlexander Aring 
11faf7d36eSAlexander Aring #define LOWPAN_DISPATCH_FIRST		0xc0
1272a5e6bbSAlexander Aring #define LOWPAN_DISPATCH_FRAG_MASK	0xf8
1372a5e6bbSAlexander Aring 
14faf7d36eSAlexander Aring #define LOWPAN_DISPATCH_NALP		0x00
15a1d8d9a5SStefan Schmidt #define LOWPAN_DISPATCH_ESC		0x40
16ad663600SAlexander Aring #define LOWPAN_DISPATCH_HC1		0x42
17ad663600SAlexander Aring #define LOWPAN_DISPATCH_DFF		0x43
18ad663600SAlexander Aring #define LOWPAN_DISPATCH_BC0		0x50
19ad663600SAlexander Aring #define LOWPAN_DISPATCH_MESH		0x80
20faf7d36eSAlexander Aring 
lowpan_give_skb_to_device(struct sk_buff * skb)2172a5e6bbSAlexander Aring static int lowpan_give_skb_to_device(struct sk_buff *skb)
224662a0daSAlexander Aring {
234662a0daSAlexander Aring 	skb->protocol = htons(ETH_P_IPV6);
241c64f147SAlexander Aring 	skb->dev->stats.rx_packets++;
251c64f147SAlexander Aring 	skb->dev->stats.rx_bytes += skb->len;
264662a0daSAlexander Aring 
2751e0e5d8SAlexander Aring 	return netif_rx(skb);
284662a0daSAlexander Aring }
294662a0daSAlexander Aring 
lowpan_rx_handlers_result(struct sk_buff * skb,lowpan_rx_result res)3072a5e6bbSAlexander Aring static int lowpan_rx_handlers_result(struct sk_buff *skb, lowpan_rx_result res)
314662a0daSAlexander Aring {
3272a5e6bbSAlexander Aring 	switch (res) {
3372a5e6bbSAlexander Aring 	case RX_CONTINUE:
3472a5e6bbSAlexander Aring 		/* nobody cared about this packet */
3572a5e6bbSAlexander Aring 		net_warn_ratelimited("%s: received unknown dispatch\n",
3672a5e6bbSAlexander Aring 				     __func__);
3772a5e6bbSAlexander Aring 
38*df561f66SGustavo A. R. Silva 		fallthrough;
3972a5e6bbSAlexander Aring 	case RX_DROP_UNUSABLE:
4072a5e6bbSAlexander Aring 		kfree_skb(skb);
4172a5e6bbSAlexander Aring 
42*df561f66SGustavo A. R. Silva 		fallthrough;
4372a5e6bbSAlexander Aring 	case RX_DROP:
4472a5e6bbSAlexander Aring 		return NET_RX_DROP;
4572a5e6bbSAlexander Aring 	case RX_QUEUED:
4672a5e6bbSAlexander Aring 		return lowpan_give_skb_to_device(skb);
4772a5e6bbSAlexander Aring 	default:
4872a5e6bbSAlexander Aring 		break;
4972a5e6bbSAlexander Aring 	}
5072a5e6bbSAlexander Aring 
5172a5e6bbSAlexander Aring 	return NET_RX_DROP;
5272a5e6bbSAlexander Aring }
5372a5e6bbSAlexander Aring 
lowpan_is_frag1(u8 dispatch)5472a5e6bbSAlexander Aring static inline bool lowpan_is_frag1(u8 dispatch)
5572a5e6bbSAlexander Aring {
5672a5e6bbSAlexander Aring 	return (dispatch & LOWPAN_DISPATCH_FRAG_MASK) == LOWPAN_DISPATCH_FRAG1;
5772a5e6bbSAlexander Aring }
5872a5e6bbSAlexander Aring 
lowpan_is_fragn(u8 dispatch)5972a5e6bbSAlexander Aring static inline bool lowpan_is_fragn(u8 dispatch)
6072a5e6bbSAlexander Aring {
6172a5e6bbSAlexander Aring 	return (dispatch & LOWPAN_DISPATCH_FRAG_MASK) == LOWPAN_DISPATCH_FRAGN;
6272a5e6bbSAlexander Aring }
6372a5e6bbSAlexander Aring 
lowpan_rx_h_frag(struct sk_buff * skb)6472a5e6bbSAlexander Aring static lowpan_rx_result lowpan_rx_h_frag(struct sk_buff *skb)
6572a5e6bbSAlexander Aring {
6672a5e6bbSAlexander Aring 	int ret;
6772a5e6bbSAlexander Aring 
6872a5e6bbSAlexander Aring 	if (!(lowpan_is_frag1(*skb_network_header(skb)) ||
6972a5e6bbSAlexander Aring 	      lowpan_is_fragn(*skb_network_header(skb))))
7072a5e6bbSAlexander Aring 		return RX_CONTINUE;
7172a5e6bbSAlexander Aring 
7272a5e6bbSAlexander Aring 	ret = lowpan_frag_rcv(skb, *skb_network_header(skb) &
7372a5e6bbSAlexander Aring 			      LOWPAN_DISPATCH_FRAG_MASK);
7472a5e6bbSAlexander Aring 	if (ret == 1)
7572a5e6bbSAlexander Aring 		return RX_QUEUED;
7672a5e6bbSAlexander Aring 
7772a5e6bbSAlexander Aring 	/* Packet is freed by lowpan_frag_rcv on error or put into the frag
7872a5e6bbSAlexander Aring 	 * bucket.
7972a5e6bbSAlexander Aring 	 */
8072a5e6bbSAlexander Aring 	return RX_DROP;
8172a5e6bbSAlexander Aring }
8272a5e6bbSAlexander Aring 
lowpan_iphc_decompress(struct sk_buff * skb)8372a5e6bbSAlexander Aring int lowpan_iphc_decompress(struct sk_buff *skb)
8472a5e6bbSAlexander Aring {
8572a5e6bbSAlexander Aring 	struct ieee802154_hdr hdr;
864662a0daSAlexander Aring 
8772a5e6bbSAlexander Aring 	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
8872a5e6bbSAlexander Aring 		return -EINVAL;
8972a5e6bbSAlexander Aring 
908911d774SAlexander Aring 	return lowpan_header_decompress(skb, skb->dev, &hdr.dest, &hdr.source);
914662a0daSAlexander Aring }
924662a0daSAlexander Aring 
lowpan_rx_h_iphc(struct sk_buff * skb)9372a5e6bbSAlexander Aring static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)
9472a5e6bbSAlexander Aring {
9572a5e6bbSAlexander Aring 	int ret;
9672a5e6bbSAlexander Aring 
9772a5e6bbSAlexander Aring 	if (!lowpan_is_iphc(*skb_network_header(skb)))
9872a5e6bbSAlexander Aring 		return RX_CONTINUE;
9972a5e6bbSAlexander Aring 
10072a5e6bbSAlexander Aring 	/* Setting datagram_offset to zero indicates non frag handling
10172a5e6bbSAlexander Aring 	 * while doing lowpan_header_decompress.
10272a5e6bbSAlexander Aring 	 */
10372a5e6bbSAlexander Aring 	lowpan_802154_cb(skb)->d_size = 0;
10472a5e6bbSAlexander Aring 
10572a5e6bbSAlexander Aring 	ret = lowpan_iphc_decompress(skb);
10672a5e6bbSAlexander Aring 	if (ret < 0)
10772a5e6bbSAlexander Aring 		return RX_DROP_UNUSABLE;
10872a5e6bbSAlexander Aring 
10972a5e6bbSAlexander Aring 	return RX_QUEUED;
11072a5e6bbSAlexander Aring }
11172a5e6bbSAlexander Aring 
lowpan_rx_h_ipv6(struct sk_buff * skb)11272a5e6bbSAlexander Aring lowpan_rx_result lowpan_rx_h_ipv6(struct sk_buff *skb)
11372a5e6bbSAlexander Aring {
11472a5e6bbSAlexander Aring 	if (!lowpan_is_ipv6(*skb_network_header(skb)))
11572a5e6bbSAlexander Aring 		return RX_CONTINUE;
11672a5e6bbSAlexander Aring 
11772a5e6bbSAlexander Aring 	/* Pull off the 1-byte of 6lowpan header. */
11872a5e6bbSAlexander Aring 	skb_pull(skb, 1);
11972a5e6bbSAlexander Aring 	return RX_QUEUED;
12072a5e6bbSAlexander Aring }
12172a5e6bbSAlexander Aring 
lowpan_is_esc(u8 dispatch)122ad663600SAlexander Aring static inline bool lowpan_is_esc(u8 dispatch)
123ad663600SAlexander Aring {
124ad663600SAlexander Aring 	return dispatch == LOWPAN_DISPATCH_ESC;
125ad663600SAlexander Aring }
126ad663600SAlexander Aring 
lowpan_rx_h_esc(struct sk_buff * skb)127ad663600SAlexander Aring static lowpan_rx_result lowpan_rx_h_esc(struct sk_buff *skb)
128ad663600SAlexander Aring {
129ad663600SAlexander Aring 	if (!lowpan_is_esc(*skb_network_header(skb)))
130ad663600SAlexander Aring 		return RX_CONTINUE;
131ad663600SAlexander Aring 
132ad663600SAlexander Aring 	net_warn_ratelimited("%s: %s\n", skb->dev->name,
133ad663600SAlexander Aring 			     "6LoWPAN ESC not supported\n");
134ad663600SAlexander Aring 
135ad663600SAlexander Aring 	return RX_DROP_UNUSABLE;
136ad663600SAlexander Aring }
137ad663600SAlexander Aring 
lowpan_is_hc1(u8 dispatch)138ad663600SAlexander Aring static inline bool lowpan_is_hc1(u8 dispatch)
139ad663600SAlexander Aring {
140ad663600SAlexander Aring 	return dispatch == LOWPAN_DISPATCH_HC1;
141ad663600SAlexander Aring }
142ad663600SAlexander Aring 
lowpan_rx_h_hc1(struct sk_buff * skb)143ad663600SAlexander Aring static lowpan_rx_result lowpan_rx_h_hc1(struct sk_buff *skb)
144ad663600SAlexander Aring {
145ad663600SAlexander Aring 	if (!lowpan_is_hc1(*skb_network_header(skb)))
146ad663600SAlexander Aring 		return RX_CONTINUE;
147ad663600SAlexander Aring 
148ad663600SAlexander Aring 	net_warn_ratelimited("%s: %s\n", skb->dev->name,
149ad663600SAlexander Aring 			     "6LoWPAN HC1 not supported\n");
150ad663600SAlexander Aring 
151ad663600SAlexander Aring 	return RX_DROP_UNUSABLE;
152ad663600SAlexander Aring }
153ad663600SAlexander Aring 
lowpan_is_dff(u8 dispatch)154ad663600SAlexander Aring static inline bool lowpan_is_dff(u8 dispatch)
155ad663600SAlexander Aring {
156ad663600SAlexander Aring 	return dispatch == LOWPAN_DISPATCH_DFF;
157ad663600SAlexander Aring }
158ad663600SAlexander Aring 
lowpan_rx_h_dff(struct sk_buff * skb)159ad663600SAlexander Aring static lowpan_rx_result lowpan_rx_h_dff(struct sk_buff *skb)
160ad663600SAlexander Aring {
161ad663600SAlexander Aring 	if (!lowpan_is_dff(*skb_network_header(skb)))
162ad663600SAlexander Aring 		return RX_CONTINUE;
163ad663600SAlexander Aring 
164ad663600SAlexander Aring 	net_warn_ratelimited("%s: %s\n", skb->dev->name,
165ad663600SAlexander Aring 			     "6LoWPAN DFF not supported\n");
166ad663600SAlexander Aring 
167ad663600SAlexander Aring 	return RX_DROP_UNUSABLE;
168ad663600SAlexander Aring }
169ad663600SAlexander Aring 
lowpan_is_bc0(u8 dispatch)170ad663600SAlexander Aring static inline bool lowpan_is_bc0(u8 dispatch)
171ad663600SAlexander Aring {
172ad663600SAlexander Aring 	return dispatch == LOWPAN_DISPATCH_BC0;
173ad663600SAlexander Aring }
174ad663600SAlexander Aring 
lowpan_rx_h_bc0(struct sk_buff * skb)175ad663600SAlexander Aring static lowpan_rx_result lowpan_rx_h_bc0(struct sk_buff *skb)
176ad663600SAlexander Aring {
177ad663600SAlexander Aring 	if (!lowpan_is_bc0(*skb_network_header(skb)))
178ad663600SAlexander Aring 		return RX_CONTINUE;
179ad663600SAlexander Aring 
180ad663600SAlexander Aring 	net_warn_ratelimited("%s: %s\n", skb->dev->name,
181ad663600SAlexander Aring 			     "6LoWPAN BC0 not supported\n");
182ad663600SAlexander Aring 
183ad663600SAlexander Aring 	return RX_DROP_UNUSABLE;
184ad663600SAlexander Aring }
185ad663600SAlexander Aring 
lowpan_is_mesh(u8 dispatch)186ad663600SAlexander Aring static inline bool lowpan_is_mesh(u8 dispatch)
187ad663600SAlexander Aring {
188ad663600SAlexander Aring 	return (dispatch & LOWPAN_DISPATCH_FIRST) == LOWPAN_DISPATCH_MESH;
189ad663600SAlexander Aring }
190ad663600SAlexander Aring 
lowpan_rx_h_mesh(struct sk_buff * skb)191ad663600SAlexander Aring static lowpan_rx_result lowpan_rx_h_mesh(struct sk_buff *skb)
192ad663600SAlexander Aring {
193ad663600SAlexander Aring 	if (!lowpan_is_mesh(*skb_network_header(skb)))
194ad663600SAlexander Aring 		return RX_CONTINUE;
195ad663600SAlexander Aring 
196ad663600SAlexander Aring 	net_warn_ratelimited("%s: %s\n", skb->dev->name,
197ad663600SAlexander Aring 			     "6LoWPAN MESH not supported\n");
198ad663600SAlexander Aring 
199ad663600SAlexander Aring 	return RX_DROP_UNUSABLE;
200ad663600SAlexander Aring }
201ad663600SAlexander Aring 
lowpan_invoke_rx_handlers(struct sk_buff * skb)20272a5e6bbSAlexander Aring static int lowpan_invoke_rx_handlers(struct sk_buff *skb)
20372a5e6bbSAlexander Aring {
20472a5e6bbSAlexander Aring 	lowpan_rx_result res;
20572a5e6bbSAlexander Aring 
20672a5e6bbSAlexander Aring #define CALL_RXH(rxh)			\
20772a5e6bbSAlexander Aring 	do {				\
20872a5e6bbSAlexander Aring 		res = rxh(skb);	\
20972a5e6bbSAlexander Aring 		if (res != RX_CONTINUE)	\
21072a5e6bbSAlexander Aring 			goto rxh_next;	\
21172a5e6bbSAlexander Aring 	} while (0)
21272a5e6bbSAlexander Aring 
21372a5e6bbSAlexander Aring 	/* likely at first */
21472a5e6bbSAlexander Aring 	CALL_RXH(lowpan_rx_h_iphc);
21572a5e6bbSAlexander Aring 	CALL_RXH(lowpan_rx_h_frag);
21672a5e6bbSAlexander Aring 	CALL_RXH(lowpan_rx_h_ipv6);
217ad663600SAlexander Aring 	CALL_RXH(lowpan_rx_h_esc);
218ad663600SAlexander Aring 	CALL_RXH(lowpan_rx_h_hc1);
219ad663600SAlexander Aring 	CALL_RXH(lowpan_rx_h_dff);
220ad663600SAlexander Aring 	CALL_RXH(lowpan_rx_h_bc0);
221ad663600SAlexander Aring 	CALL_RXH(lowpan_rx_h_mesh);
22272a5e6bbSAlexander Aring 
22372a5e6bbSAlexander Aring rxh_next:
22472a5e6bbSAlexander Aring 	return lowpan_rx_handlers_result(skb, res);
22572a5e6bbSAlexander Aring #undef CALL_RXH
22672a5e6bbSAlexander Aring }
22772a5e6bbSAlexander Aring 
lowpan_is_nalp(u8 dispatch)228faf7d36eSAlexander Aring static inline bool lowpan_is_nalp(u8 dispatch)
229faf7d36eSAlexander Aring {
230faf7d36eSAlexander Aring 	return (dispatch & LOWPAN_DISPATCH_FIRST) == LOWPAN_DISPATCH_NALP;
231faf7d36eSAlexander Aring }
232faf7d36eSAlexander Aring 
233c6fdbba3SAlexander Aring /* Lookup for reserved dispatch values at:
234c6fdbba3SAlexander Aring  * https://www.iana.org/assignments/_6lowpan-parameters/_6lowpan-parameters.xhtml#_6lowpan-parameters-1
235c6fdbba3SAlexander Aring  *
236c6fdbba3SAlexander Aring  * Last Updated: 2015-01-22
237c6fdbba3SAlexander Aring  */
lowpan_is_reserved(u8 dispatch)238c6fdbba3SAlexander Aring static inline bool lowpan_is_reserved(u8 dispatch)
239c6fdbba3SAlexander Aring {
240c6fdbba3SAlexander Aring 	return ((dispatch >= 0x44 && dispatch <= 0x4F) ||
241c6fdbba3SAlexander Aring 		(dispatch >= 0x51 && dispatch <= 0x5F) ||
242c6fdbba3SAlexander Aring 		(dispatch >= 0xc8 && dispatch <= 0xdf) ||
2433712c1c2SYang Yingliang 		dispatch >= 0xe8);
244c6fdbba3SAlexander Aring }
245c6fdbba3SAlexander Aring 
246faf7d36eSAlexander Aring /* lowpan_rx_h_check checks on generic 6LoWPAN requirements
247faf7d36eSAlexander Aring  * in MAC and 6LoWPAN header.
248faf7d36eSAlexander Aring  *
249faf7d36eSAlexander Aring  * Don't manipulate the skb here, it could be shared buffer.
250faf7d36eSAlexander Aring  */
lowpan_rx_h_check(struct sk_buff * skb)251faf7d36eSAlexander Aring static inline bool lowpan_rx_h_check(struct sk_buff *skb)
252faf7d36eSAlexander Aring {
25354552d03SAlexander Aring 	__le16 fc = ieee802154_get_fc_from_skb(skb);
25454552d03SAlexander Aring 
25554552d03SAlexander Aring 	/* check on ieee802154 conform 6LoWPAN header */
25654552d03SAlexander Aring 	if (!ieee802154_is_data(fc) ||
2570ea0b9afSAlexander Aring 	    !ieee802154_skb_is_intra_pan_addressing(fc, skb))
25854552d03SAlexander Aring 		return false;
25954552d03SAlexander Aring 
260faf7d36eSAlexander Aring 	/* check if we can dereference the dispatch */
261faf7d36eSAlexander Aring 	if (unlikely(!skb->len))
262faf7d36eSAlexander Aring 		return false;
263faf7d36eSAlexander Aring 
264c6fdbba3SAlexander Aring 	if (lowpan_is_nalp(*skb_network_header(skb)) ||
265c6fdbba3SAlexander Aring 	    lowpan_is_reserved(*skb_network_header(skb)))
266faf7d36eSAlexander Aring 		return false;
267faf7d36eSAlexander Aring 
268faf7d36eSAlexander Aring 	return true;
269faf7d36eSAlexander Aring }
270faf7d36eSAlexander Aring 
lowpan_rcv(struct sk_buff * skb,struct net_device * wdev,struct packet_type * pt,struct net_device * orig_wdev)271f4606583SAlexander Aring static int lowpan_rcv(struct sk_buff *skb, struct net_device *wdev,
272f4606583SAlexander Aring 		      struct packet_type *pt, struct net_device *orig_wdev)
2734662a0daSAlexander Aring {
274989d433dSAlexander Aring 	struct net_device *ldev;
2754662a0daSAlexander Aring 
276742c3afeSAlexander Aring 	if (wdev->type != ARPHRD_IEEE802154 ||
277faf7d36eSAlexander Aring 	    skb->pkt_type == PACKET_OTHERHOST ||
278faf7d36eSAlexander Aring 	    !lowpan_rx_h_check(skb))
279aeedebffSAlexander Aring 		goto drop;
280989d433dSAlexander Aring 
281989d433dSAlexander Aring 	ldev = wdev->ieee802154_ptr->lowpan_dev;
282989d433dSAlexander Aring 	if (!ldev || !netif_running(ldev))
283aeedebffSAlexander Aring 		goto drop;
284c0015bf3SAlexander Aring 
285f801cf40SAlexander Aring 	/* Replacing skb->dev and followed rx handlers will manipulate skb. */
2864662a0daSAlexander Aring 	skb = skb_share_check(skb, GFP_ATOMIC);
2874662a0daSAlexander Aring 	if (!skb)
288aeedebffSAlexander Aring 		goto out;
289f801cf40SAlexander Aring 	skb->dev = ldev;
2904662a0daSAlexander Aring 
29172a5e6bbSAlexander Aring 	/* When receive frag1 it's likely that we manipulate the buffer.
29272a5e6bbSAlexander Aring 	 * When recevie iphc we manipulate the data buffer. So we need
29372a5e6bbSAlexander Aring 	 * to unshare the buffer.
29472a5e6bbSAlexander Aring 	 */
29572a5e6bbSAlexander Aring 	if (lowpan_is_frag1(*skb_network_header(skb)) ||
29672a5e6bbSAlexander Aring 	    lowpan_is_iphc(*skb_network_header(skb))) {
29772a5e6bbSAlexander Aring 		skb = skb_unshare(skb, GFP_ATOMIC);
29872a5e6bbSAlexander Aring 		if (!skb)
299aeedebffSAlexander Aring 			goto out;
3004662a0daSAlexander Aring 	}
3014662a0daSAlexander Aring 
30272a5e6bbSAlexander Aring 	return lowpan_invoke_rx_handlers(skb);
303aeedebffSAlexander Aring 
304aeedebffSAlexander Aring drop:
305aeedebffSAlexander Aring 	kfree_skb(skb);
306aeedebffSAlexander Aring out:
307aeedebffSAlexander Aring 	return NET_RX_DROP;
3084662a0daSAlexander Aring }
3094662a0daSAlexander Aring 
3104662a0daSAlexander Aring static struct packet_type lowpan_packet_type = {
3114662a0daSAlexander Aring 	.type = htons(ETH_P_IEEE802154),
3124662a0daSAlexander Aring 	.func = lowpan_rcv,
3134662a0daSAlexander Aring };
3144662a0daSAlexander Aring 
lowpan_rx_init(void)3154662a0daSAlexander Aring void lowpan_rx_init(void)
3164662a0daSAlexander Aring {
3174662a0daSAlexander Aring 	dev_add_pack(&lowpan_packet_type);
3184662a0daSAlexander Aring }
3194662a0daSAlexander Aring 
lowpan_rx_exit(void)3204662a0daSAlexander Aring void lowpan_rx_exit(void)
3214662a0daSAlexander Aring {
3224662a0daSAlexander Aring 	dev_remove_pack(&lowpan_packet_type);
3234662a0daSAlexander Aring }
324