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