aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154/6lowpan.c
diff options
context:
space:
mode:
authorAlexander Smirnov <alex.bluesman.smirnov@gmail.com>2011-08-24 22:34:42 -0400
committerDavid S. Miller <davem@davemloft.net>2011-08-24 22:36:06 -0400
commit44331fe2aa0d7eed54e68484df58e9e00aee0f6e (patch)
tree02d56d565c5ec9ba61c422be0c9b2b42f5807293 /net/ieee802154/6lowpan.c
parent804cf14ea5ceca46554d5801e2817bba8116b7e5 (diff)
IEEE802.15.4: 6LoWPAN basic support
This patch provides base support for transmission of IPv6 packets as well as the formation of IPv6 link-local addresses and statelessly autoconfigured addresses on top of IEEE 802.15.4 networks. For more information please look at the RFC4944 "Compression Format for IPv6 Datagrams in Low Power and Losst Networks (6LoWPAN). Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ieee802154/6lowpan.c')
-rw-r--r--net/ieee802154/6lowpan.c885
1 files changed, 885 insertions, 0 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
new file mode 100644
index 000000000000..cf304cc8c8ef
--- /dev/null
+++ b/net/ieee802154/6lowpan.c
@@ -0,0 +1,885 @@
1/*
2 * Copyright 2011, Siemens AG
3 * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
4 */
5
6/*
7 * Based on patches from Jon Smirl <jonsmirl@gmail.com>
8 * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24/* Jon's code is based on 6lowpan implementation for Contiki which is:
25 * Copyright (c) 2008, Swedish Institute of Computer Science.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of the Institute nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 */
52
53#define DEBUG
54
55#include <linux/bitops.h>
56#include <linux/if_arp.h>
57#include <linux/module.h>
58#include <linux/moduleparam.h>
59#include <linux/netdevice.h>
60#include <net/af_ieee802154.h>
61#include <net/ieee802154.h>
62#include <net/ieee802154_netdev.h>
63#include <net/ipv6.h>
64
65#include "6lowpan.h"
66
67/* TTL uncompression values */
68static const u8 lowpan_ttl_values[] = {0, 1, 64, 255};
69
70static LIST_HEAD(lowpan_devices);
71
72/*
73 * Uncompression of linklocal:
74 * 0 -> 16 bytes from packet
75 * 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet
76 * 2 -> 2 bytes from prefix - zeroes + 2 from packet
77 * 3 -> 2 bytes from prefix - infer 8 bytes from lladdr
78 *
79 * NOTE: => the uncompress function does change 0xf to 0x10
80 * NOTE: 0x00 => no-autoconfig => unspecified
81 */
82static const u8 lowpan_unc_llconf[] = {0x0f, 0x28, 0x22, 0x20};
83
84/*
85 * Uncompression of ctx-based:
86 * 0 -> 0 bits from packet [unspecified / reserved]
87 * 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet
88 * 2 -> 8 bytes from prefix - zeroes + 2 from packet
89 * 3 -> 8 bytes from prefix - infer 8 bytes from lladdr
90 */
91static const u8 lowpan_unc_ctxconf[] = {0x00, 0x88, 0x82, 0x80};
92
93/*
94 * Uncompression of ctx-base
95 * 0 -> 0 bits from packet
96 * 1 -> 2 bytes from prefix - bunch of zeroes 5 from packet
97 * 2 -> 2 bytes from prefix - zeroes + 3 from packet
98 * 3 -> 2 bytes from prefix - infer 1 bytes from lladdr
99 */
100static const u8 lowpan_unc_mxconf[] = {0x0f, 0x25, 0x23, 0x21};
101
102/* Link local prefix */
103static const u8 lowpan_llprefix[] = {0xfe, 0x80};
104
105/* private device info */
106struct lowpan_dev_info {
107 struct net_device *real_dev; /* real WPAN device ptr */
108 struct mutex dev_list_mtx; /* mutex for list ops */
109};
110
111struct lowpan_dev_record {
112 struct net_device *ldev;
113 struct list_head list;
114};
115
116static inline struct
117lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
118{
119 return netdev_priv(dev);
120}
121
122static inline void lowpan_address_flip(u8 *src, u8 *dest)
123{
124 int i;
125 for (i = 0; i < IEEE802154_ADDR_LEN; i++)
126 (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
127}
128
129/* list of all 6lowpan devices, uses for package delivering */
130/* print data in line */
131static inline void lowpan_raw_dump_inline(const char *caller, char *msg,
132 unsigned char *buf, int len)
133{
134#ifdef DEBUG
135 if (msg)
136 pr_debug("(%s) %s: ", caller, msg);
137 print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,
138 16, 1, buf, len, false);
139#endif /* DEBUG */
140}
141
142/*
143 * print data in a table format:
144 *
145 * addr: xx xx xx xx xx xx
146 * addr: xx xx xx xx xx xx
147 * ...
148 */
149static inline void lowpan_raw_dump_table(const char *caller, char *msg,
150 unsigned char *buf, int len)
151{
152#ifdef DEBUG
153 if (msg)
154 pr_debug("(%s) %s:\n", caller, msg);
155 print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET,
156 16, 1, buf, len, false);
157#endif /* DEBUG */
158}
159
160static u8
161lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
162 const unsigned char *lladdr)
163{
164 u8 val = 0;
165
166 if (is_addr_mac_addr_based(ipaddr, lladdr))
167 val = 3; /* 0-bits */
168 else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
169 /* compress IID to 16 bits xxxx::XXXX */
170 memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
171 *hc06_ptr += 2;
172 val = 2; /* 16-bits */
173 } else {
174 /* do not compress IID => xxxx::IID */
175 memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
176 *hc06_ptr += 8;
177 val = 1; /* 64-bits */
178 }
179
180 return rol8(val, shift);
181}
182
183static void
184lowpan_uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char *lladdr)
185{
186 memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ALEN);
187 /* second bit-flip (Universe/Local) is done according RFC2464 */
188 ipaddr->s6_addr[8] ^= 0x02;
189}
190
191/*
192 * Uncompress addresses based on a prefix and a postfix with zeroes in
193 * between. If the postfix is zero in length it will use the link address
194 * to configure the IP address (autoconf style).
195 * pref_post_count takes a byte where the first nibble specify prefix count
196 * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
197 */
198static int
199lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
200 u8 const *prefix, u8 pref_post_count, unsigned char *lladdr)
201{
202 u8 prefcount = pref_post_count >> 4;
203 u8 postcount = pref_post_count & 0x0f;
204
205 /* full nibble 15 => 16 */
206 prefcount = (prefcount == 15 ? 16 : prefcount);
207 postcount = (postcount == 15 ? 16 : postcount);
208
209 if (lladdr)
210 lowpan_raw_dump_inline(__func__, "linklocal address",
211 lladdr, IEEE802154_ALEN);
212 if (prefcount > 0)
213 memcpy(ipaddr, prefix, prefcount);
214
215 if (prefcount + postcount < 16)
216 memset(&ipaddr->s6_addr[prefcount], 0,
217 16 - (prefcount + postcount));
218
219 if (postcount > 0) {
220 memcpy(&ipaddr->s6_addr[16 - postcount], skb->data, postcount);
221 skb_pull(skb, postcount);
222 } else if (prefcount > 0) {
223 if (lladdr == NULL)
224 return -EINVAL;
225
226 /* no IID based configuration if no prefix and no data */
227 lowpan_uip_ds6_set_addr_iid(ipaddr, lladdr);
228 }
229
230 pr_debug("(%s): uncompressing %d + %d => ", __func__, prefcount,
231 postcount);
232 lowpan_raw_dump_inline(NULL, NULL, ipaddr->s6_addr, 16);
233
234 return 0;
235}
236
237static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
238{
239 u8 ret;
240
241 ret = skb->data[0];
242 skb_pull(skb, 1);
243
244 return ret;
245}
246
247static int lowpan_header_create(struct sk_buff *skb,
248 struct net_device *dev,
249 unsigned short type, const void *_daddr,
250 const void *_saddr, unsigned len)
251{
252 u8 tmp, iphc0, iphc1, *hc06_ptr;
253 struct ipv6hdr *hdr;
254 const u8 *saddr = _saddr;
255 const u8 *daddr = _daddr;
256 u8 *head;
257 struct ieee802154_addr sa, da;
258
259 if (type != ETH_P_IPV6)
260 return 0;
261 /* TODO:
262 * if this package isn't ipv6 one, where should it be routed?
263 */
264 head = kzalloc(100, GFP_KERNEL);
265 if (head == NULL)
266 return -ENOMEM;
267
268 hdr = ipv6_hdr(skb);
269 hc06_ptr = head + 2;
270
271 pr_debug("(%s): IPv6 header dump:\n\tversion = %d\n\tlength = %d\n"
272 "\tnexthdr = 0x%02x\n\thop_lim = %d\n", __func__,
273 hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
274 hdr->hop_limit);
275
276 lowpan_raw_dump_table(__func__, "raw skb network header dump",
277 skb_network_header(skb), sizeof(struct ipv6hdr));
278
279 if (!saddr)
280 saddr = dev->dev_addr;
281
282 lowpan_raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
283
284 /*
285 * As we copy some bit-length fields, in the IPHC encoding bytes,
286 * we sometimes use |=
287 * If the field is 0, and the current bit value in memory is 1,
288 * this does not work. We therefore reset the IPHC encoding here
289 */
290 iphc0 = LOWPAN_DISPATCH_IPHC;
291 iphc1 = 0;
292
293 /* TODO: context lookup */
294
295 lowpan_raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
296
297 /*
298 * Traffic class, flow label
299 * If flow label is 0, compress it. If traffic class is 0, compress it
300 * We have to process both in the same time as the offset of traffic
301 * class depends on the presence of version and flow label
302 */
303
304 /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
305 tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
306 tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
307
308 if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
309 (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
310 /* flow label can be compressed */
311 iphc0 |= LOWPAN_IPHC_FL_C;
312 if ((hdr->priority == 0) &&
313 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
314 /* compress (elide) all */
315 iphc0 |= LOWPAN_IPHC_TC_C;
316 } else {
317 /* compress only the flow label */
318 *hc06_ptr = tmp;
319 hc06_ptr += 1;
320 }
321 } else {
322 /* Flow label cannot be compressed */
323 if ((hdr->priority == 0) &&
324 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
325 /* compress only traffic class */
326 iphc0 |= LOWPAN_IPHC_TC_C;
327 *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
328 memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
329 hc06_ptr += 3;
330 } else {
331 /* compress nothing */
332 memcpy(hc06_ptr, &hdr, 4);
333 /* replace the top byte with new ECN | DSCP format */
334 *hc06_ptr = tmp;
335 hc06_ptr += 4;
336 }
337 }
338
339 /* NOTE: payload length is always compressed */
340
341 /* Next Header is compress if UDP */
342 if (hdr->nexthdr == UIP_PROTO_UDP)
343 iphc0 |= LOWPAN_IPHC_NH_C;
344
345/* TODO: next header compression */
346
347 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
348 *hc06_ptr = hdr->nexthdr;
349 hc06_ptr += 1;
350 }
351
352 /*
353 * Hop limit
354 * if 1: compress, encoding is 01
355 * if 64: compress, encoding is 10
356 * if 255: compress, encoding is 11
357 * else do not compress
358 */
359 switch (hdr->hop_limit) {
360 case 1:
361 iphc0 |= LOWPAN_IPHC_TTL_1;
362 break;
363 case 64:
364 iphc0 |= LOWPAN_IPHC_TTL_64;
365 break;
366 case 255:
367 iphc0 |= LOWPAN_IPHC_TTL_255;
368 break;
369 default:
370 *hc06_ptr = hdr->hop_limit;
371 break;
372 }
373
374 /* source address compression */
375 if (is_addr_unspecified(&hdr->saddr)) {
376 pr_debug("(%s): source address is unspecified, setting SAC\n",
377 __func__);
378 iphc1 |= LOWPAN_IPHC_SAC;
379 /* TODO: context lookup */
380 } else if (is_addr_link_local(&hdr->saddr)) {
381 pr_debug("(%s): source address is link-local\n", __func__);
382 iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
383 LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr);
384 } else {
385 pr_debug("(%s): send the full source address\n", __func__);
386 memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
387 hc06_ptr += 16;
388 }
389
390 /* destination address compression */
391 if (is_addr_mcast(&hdr->daddr)) {
392 pr_debug("(%s): destination address is multicast", __func__);
393 iphc1 |= LOWPAN_IPHC_M;
394 if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
395 pr_debug("compressed to 1 octet\n");
396 iphc1 |= LOWPAN_IPHC_DAM_11;
397 /* use last byte */
398 *hc06_ptr = hdr->daddr.s6_addr[15];
399 hc06_ptr += 1;
400 } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
401 pr_debug("compressed to 4 octets\n");
402 iphc1 |= LOWPAN_IPHC_DAM_10;
403 /* second byte + the last three */
404 *hc06_ptr = hdr->daddr.s6_addr[1];
405 memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
406 hc06_ptr += 4;
407 } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
408 pr_debug("compressed to 6 octets\n");
409 iphc1 |= LOWPAN_IPHC_DAM_01;
410 /* second byte + the last five */
411 *hc06_ptr = hdr->daddr.s6_addr[1];
412 memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
413 hc06_ptr += 6;
414 } else {
415 pr_debug("using full address\n");
416 iphc1 |= LOWPAN_IPHC_DAM_00;
417 memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
418 hc06_ptr += 16;
419 }
420 } else {
421 pr_debug("(%s): destination address is unicast: ", __func__);
422 /* TODO: context lookup */
423 if (is_addr_link_local(&hdr->daddr)) {
424 pr_debug("destination address is link-local\n");
425 iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
426 LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
427 } else {
428 pr_debug("using full address\n");
429 memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
430 hc06_ptr += 16;
431 }
432 }
433
434 /* TODO: UDP header compression */
435 /* TODO: Next Header compression */
436
437 head[0] = iphc0;
438 head[1] = iphc1;
439
440 skb_pull(skb, sizeof(struct ipv6hdr));
441 memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
442
443 kfree(head);
444
445 lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
446 skb->len);
447
448 /*
449 * NOTE1: I'm still unsure about the fact that compression and WPAN
450 * header are created here and not later in the xmit. So wait for
451 * an opinion of net maintainers.
452 */
453 /*
454 * NOTE2: to be absolutely correct, we must derive PANid information
455 * from MAC subif of the 'dev' and 'real_dev' network devices, but
456 * this isn't implemented in mainline yet, so currently we assign 0xff
457 */
458 {
459 /* prepare wpan address data */
460 sa.addr_type = IEEE802154_ADDR_LONG;
461 sa.pan_id = 0xff;
462
463 da.addr_type = IEEE802154_ADDR_LONG;
464 da.pan_id = 0xff;
465
466 memcpy(&(da.hwaddr), daddr, 8);
467 memcpy(&(sa.hwaddr), saddr, 8);
468
469 mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
470 return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
471 type, (void *)&da, (void *)&sa, skb->len);
472 }
473}
474
475static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
476{
477 struct sk_buff *new;
478 struct lowpan_dev_record *entry;
479 int stat = NET_RX_SUCCESS;
480
481 new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
482 GFP_KERNEL);
483 kfree_skb(skb);
484
485 if (NULL == new)
486 return -ENOMEM;
487
488 skb_push(new, sizeof(struct ipv6hdr));
489 skb_reset_network_header(new);
490 skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
491
492 new->protocol = htons(ETH_P_IPV6);
493 new->pkt_type = PACKET_HOST;
494
495 rcu_read_lock();
496 list_for_each_entry_rcu(entry, &lowpan_devices, list)
497 if (lowpan_dev_info(entry->ldev)->real_dev == new->dev) {
498 skb = skb_copy(new, GFP_KERNEL);
499 skb->dev = entry->ldev;
500
501 if (in_interrupt())
502 stat = netif_rx(skb);
503 else
504 stat = netif_rx_ni(skb);
505 }
506 rcu_read_unlock();
507
508 kfree_skb(new);
509
510 return stat;
511}
512
513static int
514lowpan_process_data(struct sk_buff *skb)
515{
516 struct ipv6hdr hdr;
517 u8 tmp, iphc0, iphc1, num_context = 0;
518 u8 *_saddr, *_daddr;
519 int err;
520
521 lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
522 skb->len);
523 /* at least two bytes will be used for the encoding */
524 if (skb->len < 2)
525 goto drop;
526 iphc0 = lowpan_fetch_skb_u8(skb);
527 iphc1 = lowpan_fetch_skb_u8(skb);
528
529 _saddr = mac_cb(skb)->sa.hwaddr;
530 _daddr = mac_cb(skb)->da.hwaddr;
531
532 pr_debug("(%s): iphc0 = %02x, iphc1 = %02x\n", __func__, iphc0, iphc1);
533
534 /* another if the CID flag is set */
535 if (iphc1 & LOWPAN_IPHC_CID) {
536 pr_debug("(%s): CID flag is set, increase header with one\n",
537 __func__);
538 if (!skb->len)
539 goto drop;
540 num_context = lowpan_fetch_skb_u8(skb);
541 }
542
543 hdr.version = 6;
544
545 /* Traffic Class and Flow Label */
546 switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
547 /*
548 * Traffic Class and FLow Label carried in-line
549 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
550 */
551 case 0: /* 00b */
552 if (!skb->len)
553 goto drop;
554 tmp = lowpan_fetch_skb_u8(skb);
555 memcpy(&hdr.flow_lbl, &skb->data[0], 3);
556 skb_pull(skb, 3);
557 hdr.priority = ((tmp >> 2) & 0x0f);
558 hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
559 (hdr.flow_lbl[0] & 0x0f);
560 break;
561 /*
562 * Traffic class carried in-line
563 * ECN + DSCP (1 byte), Flow Label is elided
564 */
565 case 1: /* 10b */
566 if (!skb->len)
567 goto drop;
568 tmp = lowpan_fetch_skb_u8(skb);
569 hdr.priority = ((tmp >> 2) & 0x0f);
570 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
571 hdr.flow_lbl[1] = 0;
572 hdr.flow_lbl[2] = 0;
573 break;
574 /*
575 * Flow Label carried in-line
576 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
577 */
578 case 2: /* 01b */
579 if (!skb->len)
580 goto drop;
581 tmp = lowpan_fetch_skb_u8(skb);
582 hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
583 memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
584 skb_pull(skb, 2);
585 break;
586 /* Traffic Class and Flow Label are elided */
587 case 3: /* 11b */
588 hdr.priority = 0;
589 hdr.flow_lbl[0] = 0;
590 hdr.flow_lbl[1] = 0;
591 hdr.flow_lbl[2] = 0;
592 break;
593 default:
594 break;
595 }
596
597 /* Next Header */
598 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
599 /* Next header is carried inline */
600 if (!skb->len)
601 goto drop;
602 hdr.nexthdr = lowpan_fetch_skb_u8(skb);
603 pr_debug("(%s): NH flag is set, next header is carried "
604 "inline: %02x\n", __func__, hdr.nexthdr);
605 }
606
607 /* Hop Limit */
608 if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
609 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
610 else {
611 if (!skb->len)
612 goto drop;
613 hdr.hop_limit = lowpan_fetch_skb_u8(skb);
614 }
615
616 /* Extract SAM to the tmp variable */
617 tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
618
619 /* Source address uncompression */
620 pr_debug("(%s): source address stateless compression\n", __func__);
621 err = lowpan_uncompress_addr(skb, &hdr.saddr, lowpan_llprefix,
622 lowpan_unc_llconf[tmp], skb->data);
623 if (err)
624 goto drop;
625
626 /* Extract DAM to the tmp variable */
627 tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
628
629 /* check for Multicast Compression */
630 if (iphc1 & LOWPAN_IPHC_M) {
631 if (iphc1 & LOWPAN_IPHC_DAC) {
632 pr_debug("(%s): destination address context-based "
633 "multicast compression\n", __func__);
634 /* TODO: implement this */
635 } else {
636 u8 prefix[] = {0xff, 0x02};
637
638 pr_debug("(%s): destination address non-context-based"
639 " multicast compression\n", __func__);
640 if (0 < tmp && tmp < 3) {
641 if (!skb->len)
642 goto drop;
643 else
644 prefix[1] = lowpan_fetch_skb_u8(skb);
645 }
646
647 err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix,
648 lowpan_unc_mxconf[tmp], NULL);
649 if (err)
650 goto drop;
651 }
652 } else {
653 pr_debug("(%s): destination address stateless compression\n",
654 __func__);
655 err = lowpan_uncompress_addr(skb, &hdr.daddr, lowpan_llprefix,
656 lowpan_unc_llconf[tmp], skb->data);
657 if (err)
658 goto drop;
659 }
660
661 /* TODO: UDP header parse */
662
663 /* Not fragmented package */
664 hdr.payload_len = htons(skb->len);
665
666 pr_debug("(%s): skb headroom size = %d, data length = %d\n", __func__,
667 skb_headroom(skb), skb->len);
668
669 pr_debug("(%s): IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t"
670 "nexthdr = 0x%02x\n\thop_lim = %d\n", __func__, hdr.version,
671 ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit);
672
673 lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
674 sizeof(hdr));
675 return lowpan_skb_deliver(skb, &hdr);
676drop:
677 kfree(skb);
678 return -EINVAL;
679}
680
681static int lowpan_set_address(struct net_device *dev, void *p)
682{
683 struct sockaddr *sa = p;
684
685 if (netif_running(dev))
686 return -EBUSY;
687
688 /* TODO: validate addr */
689 memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
690
691 return 0;
692}
693
694static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
695{
696 int err = 0;
697
698 pr_debug("(%s): package xmit\n", __func__);
699
700 skb->dev = lowpan_dev_info(dev)->real_dev;
701 if (skb->dev == NULL) {
702 pr_debug("(%s) ERROR: no real wpan device found\n", __func__);
703 dev_kfree_skb(skb);
704 } else
705 err = dev_queue_xmit(skb);
706
707 return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
708}
709
710static void lowpan_dev_free(struct net_device *dev)
711{
712 dev_put(lowpan_dev_info(dev)->real_dev);
713 free_netdev(dev);
714}
715
716static struct header_ops lowpan_header_ops = {
717 .create = lowpan_header_create,
718};
719
720static const struct net_device_ops lowpan_netdev_ops = {
721 .ndo_start_xmit = lowpan_xmit,
722 .ndo_set_mac_address = lowpan_set_address,
723};
724
725static void lowpan_setup(struct net_device *dev)
726{
727 pr_debug("(%s)\n", __func__);
728
729 dev->addr_len = IEEE802154_ADDR_LEN;
730 memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
731 dev->type = ARPHRD_IEEE802154;
732 dev->features = NETIF_F_NO_CSUM;
733 /* Frame Control + Sequence Number + Address fields + Security Header */
734 dev->hard_header_len = 2 + 1 + 20 + 14;
735 dev->needed_tailroom = 2; /* FCS */
736 dev->mtu = 1281;
737 dev->tx_queue_len = 0;
738 dev->flags = IFF_NOARP | IFF_BROADCAST;
739 dev->watchdog_timeo = 0;
740
741 dev->netdev_ops = &lowpan_netdev_ops;
742 dev->header_ops = &lowpan_header_ops;
743 dev->destructor = lowpan_dev_free;
744}
745
746static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
747{
748 pr_debug("(%s)\n", __func__);
749
750 if (tb[IFLA_ADDRESS]) {
751 if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
752 return -EINVAL;
753 }
754 return 0;
755}
756
757static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
758 struct packet_type *pt, struct net_device *orig_dev)
759{
760 if (!netif_running(dev))
761 goto drop;
762
763 if (dev->type != ARPHRD_IEEE802154)
764 goto drop;
765
766 /* check that it's our buffer */
767 if ((skb->data[0] & 0xe0) == 0x60)
768 lowpan_process_data(skb);
769
770 return NET_RX_SUCCESS;
771
772drop:
773 kfree_skb(skb);
774 return NET_RX_DROP;
775}
776
777static int lowpan_newlink(struct net *src_net, struct net_device *dev,
778 struct nlattr *tb[], struct nlattr *data[])
779{
780 struct net_device *real_dev;
781 struct lowpan_dev_record *entry;
782
783 pr_debug("(%s)\n", __func__);
784
785 if (!tb[IFLA_LINK])
786 return -EINVAL;
787 /* find and hold real wpan device */
788 real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
789 if (!real_dev)
790 return -ENODEV;
791
792 lowpan_dev_info(dev)->real_dev = real_dev;
793 mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
794
795 entry = kzalloc(sizeof(struct lowpan_dev_record), GFP_KERNEL);
796 if (!entry)
797 return -ENOMEM;
798
799 entry->ldev = dev;
800
801 mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
802 INIT_LIST_HEAD(&entry->list);
803 list_add_tail(&entry->list, &lowpan_devices);
804 mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
805
806 register_netdevice(dev);
807
808 return 0;
809}
810
811static void lowpan_dellink(struct net_device *dev, struct list_head *head)
812{
813 struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
814 struct net_device *real_dev = lowpan_dev->real_dev;
815 struct lowpan_dev_record *entry;
816
817 ASSERT_RTNL();
818
819 mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
820 list_for_each_entry(entry, &lowpan_devices, list)
821 if (entry->ldev == dev) {
822 list_del(&entry->list);
823 kfree(entry);
824 }
825 mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
826
827 mutex_destroy(&lowpan_dev_info(dev)->dev_list_mtx);
828
829 unregister_netdevice_queue(dev, head);
830
831 dev_put(real_dev);
832}
833
834static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
835 .kind = "lowpan",
836 .priv_size = sizeof(struct lowpan_dev_info),
837 .setup = lowpan_setup,
838 .newlink = lowpan_newlink,
839 .dellink = lowpan_dellink,
840 .validate = lowpan_validate,
841};
842
843static inline int __init lowpan_netlink_init(void)
844{
845 return rtnl_link_register(&lowpan_link_ops);
846}
847
848static inline void __init lowpan_netlink_fini(void)
849{
850 rtnl_link_unregister(&lowpan_link_ops);
851}
852
853static struct packet_type lowpan_packet_type = {
854 .type = __constant_htons(ETH_P_IEEE802154),
855 .func = lowpan_rcv,
856};
857
858static int __init lowpan_init_module(void)
859{
860 int err = 0;
861
862 pr_debug("(%s)\n", __func__);
863
864 err = lowpan_netlink_init();
865 if (err < 0)
866 goto out;
867
868 dev_add_pack(&lowpan_packet_type);
869out:
870 return err;
871}
872
873static void __exit lowpan_cleanup_module(void)
874{
875 pr_debug("(%s)\n", __func__);
876
877 lowpan_netlink_fini();
878
879 dev_remove_pack(&lowpan_packet_type);
880}
881
882module_init(lowpan_init_module);
883module_exit(lowpan_cleanup_module);
884MODULE_LICENSE("GPL");
885MODULE_ALIAS_RTNL_LINK("lowpan");