aboutsummaryrefslogtreecommitdiffstats
path: root/net/6lowpan
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2014-07-11 04:24:18 -0400
committerMarcel Holtmann <marcel@holtmann.org>2014-07-11 19:53:30 -0400
commit2c6bed7cfcd3f594ed9e4d6919fa2ebea2243d19 (patch)
tree975802efd97ca552230485fe58f07229cf39710f /net/6lowpan
parent6c53823ae0e10e723131055e1e65dd6a328a228e (diff)
6lowpan: introduce new net/6lowpan directory
This patch moves generic code which is used by bluetooth and ieee802154 6lowpan to a new net/6lowpan directory. This directory contains generic 6LoWPAN code which is shared between bluetooth and ieee802154 MAC-Layer. This is the IPHC - "IPv6 Header Compression" format at the moment. Which is described by RFC 6282 [0]. The BLTE 6LoWPAN draft describes that the IPHC is the same format like IEEE 802.15.4, see [1]. Futuremore we can put more code into this directory which is shared between BLTE and IEEE 802.15.4 6LoWPAN like RFC 6775 or the routing protocol RPL RFC 6550. To avoid naming conflicts I renamed 6lowpan-y to ieee802154_6lowpan-y in net/ieee802154/Makefile. [0] http://tools.ietf.org/html/rfc6282 [1] http://tools.ietf.org/html/draft-ietf-6lowpan-btle-12#section-3.2 [2] http://tools.ietf.org/html/rfc6775 [3] http://tools.ietf.org/html/rfc6550 Signed-off-by: Alexander Aring <alex.aring@gmail.com> Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/6lowpan')
-rw-r--r--net/6lowpan/Kconfig6
-rw-r--r--net/6lowpan/Makefile3
-rw-r--r--net/6lowpan/iphc.c801
3 files changed, 810 insertions, 0 deletions
diff --git a/net/6lowpan/Kconfig b/net/6lowpan/Kconfig
new file mode 100644
index 000000000000..028a5c6d1f61
--- /dev/null
+++ b/net/6lowpan/Kconfig
@@ -0,0 +1,6 @@
1config 6LOWPAN
2 bool "6LoWPAN Support"
3 depends on IPV6
4 ---help---
5 This enables IPv6 over Low power Wireless Personal Area Network -
6 "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks.
diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile
new file mode 100644
index 000000000000..415886bb456a
--- /dev/null
+++ b/net/6lowpan/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_6LOWPAN) := 6lowpan.o
2
36lowpan-y := iphc.o
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
new file mode 100644
index 000000000000..211b5686d719
--- /dev/null
+++ b/net/6lowpan/iphc.c
@@ -0,0 +1,801 @@
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#include <linux/bitops.h>
54#include <linux/if_arp.h>
55#include <linux/module.h>
56#include <linux/netdevice.h>
57#include <net/6lowpan.h>
58#include <net/ipv6.h>
59#include <net/af_ieee802154.h>
60
61/*
62 * Uncompress address function for source and
63 * destination address(non-multicast).
64 *
65 * address_mode is sam value or dam value.
66 */
67static int uncompress_addr(struct sk_buff *skb,
68 struct in6_addr *ipaddr, const u8 address_mode,
69 const u8 *lladdr, const u8 addr_type,
70 const u8 addr_len)
71{
72 bool fail;
73
74 switch (address_mode) {
75 case LOWPAN_IPHC_ADDR_00:
76 /* for global link addresses */
77 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
78 break;
79 case LOWPAN_IPHC_ADDR_01:
80 /* fe:80::XXXX:XXXX:XXXX:XXXX */
81 ipaddr->s6_addr[0] = 0xFE;
82 ipaddr->s6_addr[1] = 0x80;
83 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
84 break;
85 case LOWPAN_IPHC_ADDR_02:
86 /* fe:80::ff:fe00:XXXX */
87 ipaddr->s6_addr[0] = 0xFE;
88 ipaddr->s6_addr[1] = 0x80;
89 ipaddr->s6_addr[11] = 0xFF;
90 ipaddr->s6_addr[12] = 0xFE;
91 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
92 break;
93 case LOWPAN_IPHC_ADDR_03:
94 fail = false;
95 switch (addr_type) {
96 case IEEE802154_ADDR_LONG:
97 /* fe:80::XXXX:XXXX:XXXX:XXXX
98 * \_________________/
99 * hwaddr
100 */
101 ipaddr->s6_addr[0] = 0xFE;
102 ipaddr->s6_addr[1] = 0x80;
103 memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
104 /* second bit-flip (Universe/Local)
105 * is done according RFC2464
106 */
107 ipaddr->s6_addr[8] ^= 0x02;
108 break;
109 case IEEE802154_ADDR_SHORT:
110 /* fe:80::ff:fe00:XXXX
111 * \__/
112 * short_addr
113 *
114 * Universe/Local bit is zero.
115 */
116 ipaddr->s6_addr[0] = 0xFE;
117 ipaddr->s6_addr[1] = 0x80;
118 ipaddr->s6_addr[11] = 0xFF;
119 ipaddr->s6_addr[12] = 0xFE;
120 ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
121 break;
122 default:
123 pr_debug("Invalid addr_type set\n");
124 return -EINVAL;
125 }
126 break;
127 default:
128 pr_debug("Invalid address mode value: 0x%x\n", address_mode);
129 return -EINVAL;
130 }
131
132 if (fail) {
133 pr_debug("Failed to fetch skb data\n");
134 return -EIO;
135 }
136
137 raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
138 ipaddr->s6_addr, 16);
139
140 return 0;
141}
142
143/*
144 * Uncompress address function for source context
145 * based address(non-multicast).
146 */
147static int uncompress_context_based_src_addr(struct sk_buff *skb,
148 struct in6_addr *ipaddr,
149 const u8 sam)
150{
151 switch (sam) {
152 case LOWPAN_IPHC_ADDR_00:
153 /* unspec address ::
154 * Do nothing, address is already ::
155 */
156 break;
157 case LOWPAN_IPHC_ADDR_01:
158 /* TODO */
159 case LOWPAN_IPHC_ADDR_02:
160 /* TODO */
161 case LOWPAN_IPHC_ADDR_03:
162 /* TODO */
163 netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
164 return -EINVAL;
165 default:
166 pr_debug("Invalid sam value: 0x%x\n", sam);
167 return -EINVAL;
168 }
169
170 raw_dump_inline(NULL,
171 "Reconstructed context based ipv6 src addr is",
172 ipaddr->s6_addr, 16);
173
174 return 0;
175}
176
177static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
178 struct net_device *dev, skb_delivery_cb deliver_skb)
179{
180 struct sk_buff *new;
181 int stat;
182
183 new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
184 GFP_ATOMIC);
185 kfree_skb(skb);
186
187 if (!new)
188 return -ENOMEM;
189
190 skb_push(new, sizeof(struct ipv6hdr));
191 skb_reset_network_header(new);
192 skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
193
194 new->protocol = htons(ETH_P_IPV6);
195 new->pkt_type = PACKET_HOST;
196 new->dev = dev;
197
198 raw_dump_table(__func__, "raw skb data dump before receiving",
199 new->data, new->len);
200
201 stat = deliver_skb(new, dev);
202
203 kfree_skb(new);
204
205 return stat;
206}
207
208/* Uncompress function for multicast destination address,
209 * when M bit is set.
210 */
211static int
212lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
213 struct in6_addr *ipaddr,
214 const u8 dam)
215{
216 bool fail;
217
218 switch (dam) {
219 case LOWPAN_IPHC_DAM_00:
220 /* 00: 128 bits. The full address
221 * is carried in-line.
222 */
223 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
224 break;
225 case LOWPAN_IPHC_DAM_01:
226 /* 01: 48 bits. The address takes
227 * the form ffXX::00XX:XXXX:XXXX.
228 */
229 ipaddr->s6_addr[0] = 0xFF;
230 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
231 fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
232 break;
233 case LOWPAN_IPHC_DAM_10:
234 /* 10: 32 bits. The address takes
235 * the form ffXX::00XX:XXXX.
236 */
237 ipaddr->s6_addr[0] = 0xFF;
238 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
239 fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
240 break;
241 case LOWPAN_IPHC_DAM_11:
242 /* 11: 8 bits. The address takes
243 * the form ff02::00XX.
244 */
245 ipaddr->s6_addr[0] = 0xFF;
246 ipaddr->s6_addr[1] = 0x02;
247 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
248 break;
249 default:
250 pr_debug("DAM value has a wrong value: 0x%x\n", dam);
251 return -EINVAL;
252 }
253
254 if (fail) {
255 pr_debug("Failed to fetch skb data\n");
256 return -EIO;
257 }
258
259 raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
260 ipaddr->s6_addr, 16);
261
262 return 0;
263}
264
265static int
266uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
267{
268 bool fail;
269 u8 tmp = 0, val = 0;
270
271 if (!uh)
272 goto err;
273
274 fail = lowpan_fetch_skb(skb, &tmp, 1);
275
276 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
277 pr_debug("UDP header uncompression\n");
278 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
279 case LOWPAN_NHC_UDP_CS_P_00:
280 fail |= lowpan_fetch_skb(skb, &uh->source, 2);
281 fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
282 break;
283 case LOWPAN_NHC_UDP_CS_P_01:
284 fail |= lowpan_fetch_skb(skb, &uh->source, 2);
285 fail |= lowpan_fetch_skb(skb, &val, 1);
286 uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
287 break;
288 case LOWPAN_NHC_UDP_CS_P_10:
289 fail |= lowpan_fetch_skb(skb, &val, 1);
290 uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
291 fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
292 break;
293 case LOWPAN_NHC_UDP_CS_P_11:
294 fail |= lowpan_fetch_skb(skb, &val, 1);
295 uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
296 (val >> 4));
297 uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
298 (val & 0x0f));
299 break;
300 default:
301 pr_debug("ERROR: unknown UDP format\n");
302 goto err;
303 break;
304 }
305
306 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
307 ntohs(uh->source), ntohs(uh->dest));
308
309 /* checksum */
310 if (tmp & LOWPAN_NHC_UDP_CS_C) {
311 pr_debug_ratelimited("checksum elided currently not supported\n");
312 goto err;
313 } else {
314 fail |= lowpan_fetch_skb(skb, &uh->check, 2);
315 }
316
317 /*
318 * UDP lenght needs to be infered from the lower layers
319 * here, we obtain the hint from the remaining size of the
320 * frame
321 */
322 uh->len = htons(skb->len + sizeof(struct udphdr));
323 pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
324 } else {
325 pr_debug("ERROR: unsupported NH format\n");
326 goto err;
327 }
328
329 if (fail)
330 goto err;
331
332 return 0;
333err:
334 return -EINVAL;
335}
336
337/* TTL uncompression values */
338static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
339
340int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
341 const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
342 const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
343 u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb)
344{
345 struct ipv6hdr hdr = {};
346 u8 tmp, num_context = 0;
347 int err;
348
349 raw_dump_table(__func__, "raw skb data dump uncompressed",
350 skb->data, skb->len);
351
352 /* another if the CID flag is set */
353 if (iphc1 & LOWPAN_IPHC_CID) {
354 pr_debug("CID flag is set, increase header with one\n");
355 if (lowpan_fetch_skb_u8(skb, &num_context))
356 goto drop;
357 }
358
359 hdr.version = 6;
360
361 /* Traffic Class and Flow Label */
362 switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
363 /*
364 * Traffic Class and FLow Label carried in-line
365 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
366 */
367 case 0: /* 00b */
368 if (lowpan_fetch_skb_u8(skb, &tmp))
369 goto drop;
370
371 memcpy(&hdr.flow_lbl, &skb->data[0], 3);
372 skb_pull(skb, 3);
373 hdr.priority = ((tmp >> 2) & 0x0f);
374 hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
375 (hdr.flow_lbl[0] & 0x0f);
376 break;
377 /*
378 * Traffic class carried in-line
379 * ECN + DSCP (1 byte), Flow Label is elided
380 */
381 case 2: /* 10b */
382 if (lowpan_fetch_skb_u8(skb, &tmp))
383 goto drop;
384
385 hdr.priority = ((tmp >> 2) & 0x0f);
386 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
387 break;
388 /*
389 * Flow Label carried in-line
390 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
391 */
392 case 1: /* 01b */
393 if (lowpan_fetch_skb_u8(skb, &tmp))
394 goto drop;
395
396 hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
397 memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
398 skb_pull(skb, 2);
399 break;
400 /* Traffic Class and Flow Label are elided */
401 case 3: /* 11b */
402 break;
403 default:
404 break;
405 }
406
407 /* Next Header */
408 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
409 /* Next header is carried inline */
410 if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
411 goto drop;
412
413 pr_debug("NH flag is set, next header carried inline: %02x\n",
414 hdr.nexthdr);
415 }
416
417 /* Hop Limit */
418 if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
419 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
420 else {
421 if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
422 goto drop;
423 }
424
425 /* Extract SAM to the tmp variable */
426 tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
427
428 if (iphc1 & LOWPAN_IPHC_SAC) {
429 /* Source address context based uncompression */
430 pr_debug("SAC bit is set. Handle context based source address.\n");
431 err = uncompress_context_based_src_addr(
432 skb, &hdr.saddr, tmp);
433 } else {
434 /* Source address uncompression */
435 pr_debug("source address stateless compression\n");
436 err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
437 saddr_type, saddr_len);
438 }
439
440 /* Check on error of previous branch */
441 if (err)
442 goto drop;
443
444 /* Extract DAM to the tmp variable */
445 tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
446
447 /* check for Multicast Compression */
448 if (iphc1 & LOWPAN_IPHC_M) {
449 if (iphc1 & LOWPAN_IPHC_DAC) {
450 pr_debug("dest: context-based mcast compression\n");
451 /* TODO: implement this */
452 } else {
453 err = lowpan_uncompress_multicast_daddr(
454 skb, &hdr.daddr, tmp);
455 if (err)
456 goto drop;
457 }
458 } else {
459 err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
460 daddr_type, daddr_len);
461 pr_debug("dest: stateless compression mode %d dest %pI6c\n",
462 tmp, &hdr.daddr);
463 if (err)
464 goto drop;
465 }
466
467 /* UDP data uncompression */
468 if (iphc0 & LOWPAN_IPHC_NH_C) {
469 struct udphdr uh;
470 struct sk_buff *new;
471 if (uncompress_udp_header(skb, &uh))
472 goto drop;
473
474 /*
475 * replace the compressed UDP head by the uncompressed UDP
476 * header
477 */
478 new = skb_copy_expand(skb, sizeof(struct udphdr),
479 skb_tailroom(skb), GFP_ATOMIC);
480 kfree_skb(skb);
481
482 if (!new)
483 return -ENOMEM;
484
485 skb = new;
486
487 skb_push(skb, sizeof(struct udphdr));
488 skb_reset_transport_header(skb);
489 skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
490
491 raw_dump_table(__func__, "raw UDP header dump",
492 (u8 *)&uh, sizeof(uh));
493
494 hdr.nexthdr = UIP_PROTO_UDP;
495 }
496
497 hdr.payload_len = htons(skb->len);
498
499 pr_debug("skb headroom size = %d, data length = %d\n",
500 skb_headroom(skb), skb->len);
501
502 pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t"
503 "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n",
504 hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
505 hdr.hop_limit, &hdr.daddr);
506
507 raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
508 sizeof(hdr));
509
510 return skb_deliver(skb, &hdr, dev, deliver_skb);
511
512drop:
513 kfree_skb(skb);
514 return -EINVAL;
515}
516EXPORT_SYMBOL_GPL(lowpan_process_data);
517
518static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
519 const struct in6_addr *ipaddr,
520 const unsigned char *lladdr)
521{
522 u8 val = 0;
523
524 if (is_addr_mac_addr_based(ipaddr, lladdr)) {
525 val = 3; /* 0-bits */
526 pr_debug("address compression 0 bits\n");
527 } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
528 /* compress IID to 16 bits xxxx::XXXX */
529 memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
530 *hc06_ptr += 2;
531 val = 2; /* 16-bits */
532 raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
533 *hc06_ptr - 2, 2);
534 } else {
535 /* do not compress IID => xxxx::IID */
536 memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
537 *hc06_ptr += 8;
538 val = 1; /* 64-bits */
539 raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
540 *hc06_ptr - 8, 8);
541 }
542
543 return rol8(val, shift);
544}
545
546static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
547{
548 struct udphdr *uh = udp_hdr(skb);
549 u8 tmp;
550
551 if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
552 LOWPAN_NHC_UDP_4BIT_PORT) &&
553 ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
554 LOWPAN_NHC_UDP_4BIT_PORT)) {
555 pr_debug("UDP header: both ports compression to 4 bits\n");
556 /* compression value */
557 tmp = LOWPAN_NHC_UDP_CS_P_11;
558 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
559 /* source and destination port */
560 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
561 ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
562 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
563 } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
564 LOWPAN_NHC_UDP_8BIT_PORT) {
565 pr_debug("UDP header: remove 8 bits of dest\n");
566 /* compression value */
567 tmp = LOWPAN_NHC_UDP_CS_P_01;
568 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
569 /* source port */
570 lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
571 /* destination port */
572 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
573 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
574 } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
575 LOWPAN_NHC_UDP_8BIT_PORT) {
576 pr_debug("UDP header: remove 8 bits of source\n");
577 /* compression value */
578 tmp = LOWPAN_NHC_UDP_CS_P_10;
579 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
580 /* source port */
581 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
582 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
583 /* destination port */
584 lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
585 } else {
586 pr_debug("UDP header: can't compress\n");
587 /* compression value */
588 tmp = LOWPAN_NHC_UDP_CS_P_00;
589 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
590 /* source port */
591 lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
592 /* destination port */
593 lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
594 }
595
596 /* checksum is always inline */
597 lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check));
598
599 /* skip the UDP header */
600 skb_pull(skb, sizeof(struct udphdr));
601}
602
603int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
604 unsigned short type, const void *_daddr,
605 const void *_saddr, unsigned int len)
606{
607 u8 tmp, iphc0, iphc1, *hc06_ptr;
608 struct ipv6hdr *hdr;
609 u8 head[100] = {};
610
611 if (type != ETH_P_IPV6)
612 return -EINVAL;
613
614 hdr = ipv6_hdr(skb);
615 hc06_ptr = head + 2;
616
617 pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n"
618 "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n",
619 hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
620 hdr->hop_limit, &hdr->daddr);
621
622 raw_dump_table(__func__, "raw skb network header dump",
623 skb_network_header(skb), sizeof(struct ipv6hdr));
624
625 /*
626 * As we copy some bit-length fields, in the IPHC encoding bytes,
627 * we sometimes use |=
628 * If the field is 0, and the current bit value in memory is 1,
629 * this does not work. We therefore reset the IPHC encoding here
630 */
631 iphc0 = LOWPAN_DISPATCH_IPHC;
632 iphc1 = 0;
633
634 /* TODO: context lookup */
635
636 raw_dump_inline(__func__, "saddr",
637 (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
638 raw_dump_inline(__func__, "daddr",
639 (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
640
641 raw_dump_table(__func__,
642 "sending raw skb network uncompressed packet",
643 skb->data, skb->len);
644
645 /*
646 * Traffic class, flow label
647 * If flow label is 0, compress it. If traffic class is 0, compress it
648 * We have to process both in the same time as the offset of traffic
649 * class depends on the presence of version and flow label
650 */
651
652 /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
653 tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
654 tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
655
656 if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
657 (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
658 /* flow label can be compressed */
659 iphc0 |= LOWPAN_IPHC_FL_C;
660 if ((hdr->priority == 0) &&
661 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
662 /* compress (elide) all */
663 iphc0 |= LOWPAN_IPHC_TC_C;
664 } else {
665 /* compress only the flow label */
666 *hc06_ptr = tmp;
667 hc06_ptr += 1;
668 }
669 } else {
670 /* Flow label cannot be compressed */
671 if ((hdr->priority == 0) &&
672 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
673 /* compress only traffic class */
674 iphc0 |= LOWPAN_IPHC_TC_C;
675 *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
676 memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
677 hc06_ptr += 3;
678 } else {
679 /* compress nothing */
680 memcpy(hc06_ptr, hdr, 4);
681 /* replace the top byte with new ECN | DSCP format */
682 *hc06_ptr = tmp;
683 hc06_ptr += 4;
684 }
685 }
686
687 /* NOTE: payload length is always compressed */
688
689 /* Next Header is compress if UDP */
690 if (hdr->nexthdr == UIP_PROTO_UDP)
691 iphc0 |= LOWPAN_IPHC_NH_C;
692
693 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
694 *hc06_ptr = hdr->nexthdr;
695 hc06_ptr += 1;
696 }
697
698 /*
699 * Hop limit
700 * if 1: compress, encoding is 01
701 * if 64: compress, encoding is 10
702 * if 255: compress, encoding is 11
703 * else do not compress
704 */
705 switch (hdr->hop_limit) {
706 case 1:
707 iphc0 |= LOWPAN_IPHC_TTL_1;
708 break;
709 case 64:
710 iphc0 |= LOWPAN_IPHC_TTL_64;
711 break;
712 case 255:
713 iphc0 |= LOWPAN_IPHC_TTL_255;
714 break;
715 default:
716 *hc06_ptr = hdr->hop_limit;
717 hc06_ptr += 1;
718 break;
719 }
720
721 /* source address compression */
722 if (is_addr_unspecified(&hdr->saddr)) {
723 pr_debug("source address is unspecified, setting SAC\n");
724 iphc1 |= LOWPAN_IPHC_SAC;
725 /* TODO: context lookup */
726 } else if (is_addr_link_local(&hdr->saddr)) {
727 iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
728 LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr);
729 pr_debug("source address unicast link-local %pI6c "
730 "iphc1 0x%02x\n", &hdr->saddr, iphc1);
731 } else {
732 pr_debug("send the full source address\n");
733 memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
734 hc06_ptr += 16;
735 }
736
737 /* destination address compression */
738 if (is_addr_mcast(&hdr->daddr)) {
739 pr_debug("destination address is multicast: ");
740 iphc1 |= LOWPAN_IPHC_M;
741 if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
742 pr_debug("compressed to 1 octet\n");
743 iphc1 |= LOWPAN_IPHC_DAM_11;
744 /* use last byte */
745 *hc06_ptr = hdr->daddr.s6_addr[15];
746 hc06_ptr += 1;
747 } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
748 pr_debug("compressed to 4 octets\n");
749 iphc1 |= LOWPAN_IPHC_DAM_10;
750 /* second byte + the last three */
751 *hc06_ptr = hdr->daddr.s6_addr[1];
752 memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
753 hc06_ptr += 4;
754 } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
755 pr_debug("compressed to 6 octets\n");
756 iphc1 |= LOWPAN_IPHC_DAM_01;
757 /* second byte + the last five */
758 *hc06_ptr = hdr->daddr.s6_addr[1];
759 memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
760 hc06_ptr += 6;
761 } else {
762 pr_debug("using full address\n");
763 iphc1 |= LOWPAN_IPHC_DAM_00;
764 memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
765 hc06_ptr += 16;
766 }
767 } else {
768 /* TODO: context lookup */
769 if (is_addr_link_local(&hdr->daddr)) {
770 iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
771 LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
772 pr_debug("dest address unicast link-local %pI6c "
773 "iphc1 0x%02x\n", &hdr->daddr, iphc1);
774 } else {
775 pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
776 memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
777 hc06_ptr += 16;
778 }
779 }
780
781 /* UDP header compression */
782 if (hdr->nexthdr == UIP_PROTO_UDP)
783 compress_udp_header(&hc06_ptr, skb);
784
785 head[0] = iphc0;
786 head[1] = iphc1;
787
788 skb_pull(skb, sizeof(struct ipv6hdr));
789 skb_reset_transport_header(skb);
790 memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
791 skb_reset_network_header(skb);
792
793 pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len);
794
795 raw_dump_table(__func__, "raw skb data dump compressed",
796 skb->data, skb->len);
797 return 0;
798}
799EXPORT_SYMBOL_GPL(lowpan_header_compress);
800
801MODULE_LICENSE("GPL");