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