aboutsummaryrefslogtreecommitdiffstats
path: root/net/6lowpan
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-07-28 20:36:25 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-28 20:36:25 -0400
commit3fd0202a0dfe07d255c5462d7d0e27673ca10430 (patch)
tree126483df9ff404e0d31cdcad18ad4280df06d89f /net/6lowpan
parenta67eed571aa505f51a4d02cab765a9d4f6ef80c4 (diff)
parent9a244409d0b0cf3b1e46f1dc331f2c718597fae0 (diff)
Merge tag 'master-2014-07-25' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== pull request: wireless-next 2014-07-25 Please pull this batch of updates intended for the 3.17 stream! For the mac80211 bits, Johannes says: "We have a lot of TDLS patches, among them a fix that should make hwsim tests happy again. The rest, this time, is mostly small fixes." For the Bluetooth bits, Gustavo says: "Some more patches for 3.17. The most important change here is the move of the 6lowpan code to net/6lowpan. It has been agreed with Davem that this change will go through the bluetooth tree. The rest are mostly clean up and fixes." and, "Here follows some more patches for 3.17. These are mostly fixes to what we've sent to you before for next merge window." For the iwlwifi bits, Emmanuel says: "I have the usual amount of BT Coex stuff. Arik continues to work on TDLS and Ariej contributes a few things for HS2.0. I added a few more things to the firmware debugging infrastructure. Eran fixes a small bug - pretty normal content." And for the Atheros bits, Kalle says: "For ath6kl me and Jessica added support for ar6004 hw3.0, our latest version of ar6004. For ath10k Janusz added a printout so that it's easier to check what ath10k kconfig options are enabled. He also added a debugfs file to configure maximum amsdu and ampdu values. Also we had few fixes as usual." On top of that is the usual large batch of various driver updates -- brcmfmac, mwifiex, the TI drivers, and wil6210 all get some action. RafaƂ has also been very busy with b43 and related updates. Also, I pulled the wireless tree into this in order to resolve a merge conflict... P.S. The change to fs/compat_ioctl.c reflects a name change in a Bluetooth header file... ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/6lowpan')
-rw-r--r--net/6lowpan/Kconfig6
-rw-r--r--net/6lowpan/Makefile3
-rw-r--r--net/6lowpan/iphc.c791
3 files changed, 800 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..a1b7117a9600
--- /dev/null
+++ b/net/6lowpan/iphc.c
@@ -0,0 +1,791 @@
1/*
2 * Copyright 2011, Siemens AG
3 * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
4 */
5
6/* Based on patches from Jon Smirl <jonsmirl@gmail.com>
7 * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23/* Jon's code is based on 6lowpan implementation for Contiki which is:
24 * Copyright (c) 2008, Swedish Institute of Computer Science.
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. Neither the name of the Institute nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 */
51
52#include <linux/bitops.h>
53#include <linux/if_arp.h>
54#include <linux/module.h>
55#include <linux/netdevice.h>
56#include <net/6lowpan.h>
57#include <net/ipv6.h>
58#include <net/af_ieee802154.h>
59
60/* Uncompress address function for source and
61 * destination address(non-multicast).
62 *
63 * address_mode is sam value or dam value.
64 */
65static int uncompress_addr(struct sk_buff *skb,
66 struct in6_addr *ipaddr, const u8 address_mode,
67 const u8 *lladdr, const u8 addr_type,
68 const u8 addr_len)
69{
70 bool fail;
71
72 switch (address_mode) {
73 case LOWPAN_IPHC_ADDR_00:
74 /* for global link addresses */
75 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
76 break;
77 case LOWPAN_IPHC_ADDR_01:
78 /* fe:80::XXXX:XXXX:XXXX:XXXX */
79 ipaddr->s6_addr[0] = 0xFE;
80 ipaddr->s6_addr[1] = 0x80;
81 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
82 break;
83 case LOWPAN_IPHC_ADDR_02:
84 /* fe:80::ff:fe00:XXXX */
85 ipaddr->s6_addr[0] = 0xFE;
86 ipaddr->s6_addr[1] = 0x80;
87 ipaddr->s6_addr[11] = 0xFF;
88 ipaddr->s6_addr[12] = 0xFE;
89 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
90 break;
91 case LOWPAN_IPHC_ADDR_03:
92 fail = false;
93 switch (addr_type) {
94 case IEEE802154_ADDR_LONG:
95 /* fe:80::XXXX:XXXX:XXXX:XXXX
96 * \_________________/
97 * hwaddr
98 */
99 ipaddr->s6_addr[0] = 0xFE;
100 ipaddr->s6_addr[1] = 0x80;
101 memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
102 /* second bit-flip (Universe/Local)
103 * is done according RFC2464
104 */
105 ipaddr->s6_addr[8] ^= 0x02;
106 break;
107 case IEEE802154_ADDR_SHORT:
108 /* fe:80::ff:fe00:XXXX
109 * \__/
110 * short_addr
111 *
112 * Universe/Local bit is zero.
113 */
114 ipaddr->s6_addr[0] = 0xFE;
115 ipaddr->s6_addr[1] = 0x80;
116 ipaddr->s6_addr[11] = 0xFF;
117 ipaddr->s6_addr[12] = 0xFE;
118 ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
119 break;
120 default:
121 pr_debug("Invalid addr_type set\n");
122 return -EINVAL;
123 }
124 break;
125 default:
126 pr_debug("Invalid address mode value: 0x%x\n", address_mode);
127 return -EINVAL;
128 }
129
130 if (fail) {
131 pr_debug("Failed to fetch skb data\n");
132 return -EIO;
133 }
134
135 raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
136 ipaddr->s6_addr, 16);
137
138 return 0;
139}
140
141/* Uncompress address function for source context
142 * based address(non-multicast).
143 */
144static int uncompress_context_based_src_addr(struct sk_buff *skb,
145 struct in6_addr *ipaddr,
146 const u8 sam)
147{
148 switch (sam) {
149 case LOWPAN_IPHC_ADDR_00:
150 /* unspec address ::
151 * Do nothing, address is already ::
152 */
153 break;
154 case LOWPAN_IPHC_ADDR_01:
155 /* TODO */
156 case LOWPAN_IPHC_ADDR_02:
157 /* TODO */
158 case LOWPAN_IPHC_ADDR_03:
159 /* TODO */
160 netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
161 return -EINVAL;
162 default:
163 pr_debug("Invalid sam value: 0x%x\n", sam);
164 return -EINVAL;
165 }
166
167 raw_dump_inline(NULL,
168 "Reconstructed context based ipv6 src addr is",
169 ipaddr->s6_addr, 16);
170
171 return 0;
172}
173
174static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
175 struct net_device *dev, skb_delivery_cb deliver_skb)
176{
177 struct sk_buff *new;
178 int stat;
179
180 new = skb_copy_expand(skb, sizeof(struct ipv6hdr),
181 skb_tailroom(skb), GFP_ATOMIC);
182 kfree_skb(skb);
183
184 if (!new)
185 return -ENOMEM;
186
187 skb_push(new, sizeof(struct ipv6hdr));
188 skb_reset_network_header(new);
189 skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
190
191 new->protocol = htons(ETH_P_IPV6);
192 new->pkt_type = PACKET_HOST;
193 new->dev = dev;
194
195 raw_dump_table(__func__, "raw skb data dump before receiving",
196 new->data, new->len);
197
198 stat = deliver_skb(new, dev);
199
200 kfree_skb(new);
201
202 return stat;
203}
204
205/* Uncompress function for multicast destination address,
206 * when M bit is set.
207 */
208static int
209lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
210 struct in6_addr *ipaddr,
211 const u8 dam)
212{
213 bool fail;
214
215 switch (dam) {
216 case LOWPAN_IPHC_DAM_00:
217 /* 00: 128 bits. The full address
218 * is carried in-line.
219 */
220 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
221 break;
222 case LOWPAN_IPHC_DAM_01:
223 /* 01: 48 bits. The address takes
224 * the form ffXX::00XX:XXXX:XXXX.
225 */
226 ipaddr->s6_addr[0] = 0xFF;
227 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
228 fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
229 break;
230 case LOWPAN_IPHC_DAM_10:
231 /* 10: 32 bits. The address takes
232 * the form ffXX::00XX:XXXX.
233 */
234 ipaddr->s6_addr[0] = 0xFF;
235 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
236 fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
237 break;
238 case LOWPAN_IPHC_DAM_11:
239 /* 11: 8 bits. The address takes
240 * the form ff02::00XX.
241 */
242 ipaddr->s6_addr[0] = 0xFF;
243 ipaddr->s6_addr[1] = 0x02;
244 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
245 break;
246 default:
247 pr_debug("DAM value has a wrong value: 0x%x\n", dam);
248 return -EINVAL;
249 }
250
251 if (fail) {
252 pr_debug("Failed to fetch skb data\n");
253 return -EIO;
254 }
255
256 raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
257 ipaddr->s6_addr, 16);
258
259 return 0;
260}
261
262static int
263uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
264{
265 bool fail;
266 u8 tmp = 0, val = 0;
267
268 if (!uh)
269 goto err;
270
271 fail = lowpan_fetch_skb(skb, &tmp, 1);
272
273 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
274 pr_debug("UDP header uncompression\n");
275 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
276 case LOWPAN_NHC_UDP_CS_P_00:
277 fail |= lowpan_fetch_skb(skb, &uh->source, 2);
278 fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
279 break;
280 case LOWPAN_NHC_UDP_CS_P_01:
281 fail |= lowpan_fetch_skb(skb, &uh->source, 2);
282 fail |= lowpan_fetch_skb(skb, &val, 1);
283 uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
284 break;
285 case LOWPAN_NHC_UDP_CS_P_10:
286 fail |= lowpan_fetch_skb(skb, &val, 1);
287 uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
288 fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
289 break;
290 case LOWPAN_NHC_UDP_CS_P_11:
291 fail |= lowpan_fetch_skb(skb, &val, 1);
292 uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
293 (val >> 4));
294 uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
295 (val & 0x0f));
296 break;
297 default:
298 pr_debug("ERROR: unknown UDP format\n");
299 goto err;
300 }
301
302 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
303 ntohs(uh->source), ntohs(uh->dest));
304
305 /* checksum */
306 if (tmp & LOWPAN_NHC_UDP_CS_C) {
307 pr_debug_ratelimited("checksum elided currently not supported\n");
308 goto err;
309 } else {
310 fail |= lowpan_fetch_skb(skb, &uh->check, 2);
311 }
312
313 /* UDP lenght needs to be infered from the lower layers
314 * here, we obtain the hint from the remaining size of the
315 * frame
316 */
317 uh->len = htons(skb->len + sizeof(struct udphdr));
318 pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
319 } else {
320 pr_debug("ERROR: unsupported NH format\n");
321 goto err;
322 }
323
324 if (fail)
325 goto err;
326
327 return 0;
328err:
329 return -EINVAL;
330}
331
332/* TTL uncompression values */
333static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
334
335int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
336 const u8 *saddr, const u8 saddr_type,
337 const u8 saddr_len, const u8 *daddr,
338 const u8 daddr_type, const u8 daddr_len,
339 u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb)
340{
341 struct ipv6hdr hdr = {};
342 u8 tmp, num_context = 0;
343 int err;
344
345 raw_dump_table(__func__, "raw skb data dump uncompressed",
346 skb->data, skb->len);
347
348 /* another if the CID flag is set */
349 if (iphc1 & LOWPAN_IPHC_CID) {
350 pr_debug("CID flag is set, increase header with one\n");
351 if (lowpan_fetch_skb_u8(skb, &num_context))
352 goto drop;
353 }
354
355 hdr.version = 6;
356
357 /* Traffic Class and Flow Label */
358 switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
359 /* Traffic Class and FLow Label carried in-line
360 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
361 */
362 case 0: /* 00b */
363 if (lowpan_fetch_skb_u8(skb, &tmp))
364 goto drop;
365
366 memcpy(&hdr.flow_lbl, &skb->data[0], 3);
367 skb_pull(skb, 3);
368 hdr.priority = ((tmp >> 2) & 0x0f);
369 hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
370 (hdr.flow_lbl[0] & 0x0f);
371 break;
372 /* Traffic class carried in-line
373 * ECN + DSCP (1 byte), Flow Label is elided
374 */
375 case 2: /* 10b */
376 if (lowpan_fetch_skb_u8(skb, &tmp))
377 goto drop;
378
379 hdr.priority = ((tmp >> 2) & 0x0f);
380 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
381 break;
382 /* Flow Label carried in-line
383 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
384 */
385 case 1: /* 01b */
386 if (lowpan_fetch_skb_u8(skb, &tmp))
387 goto drop;
388
389 hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
390 memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
391 skb_pull(skb, 2);
392 break;
393 /* Traffic Class and Flow Label are elided */
394 case 3: /* 11b */
395 break;
396 default:
397 break;
398 }
399
400 /* Next Header */
401 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
402 /* Next header is carried inline */
403 if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
404 goto drop;
405
406 pr_debug("NH flag is set, next header carried inline: %02x\n",
407 hdr.nexthdr);
408 }
409
410 /* Hop Limit */
411 if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
412 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
413 } else {
414 if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
415 goto drop;
416 }
417
418 /* Extract SAM to the tmp variable */
419 tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
420
421 if (iphc1 & LOWPAN_IPHC_SAC) {
422 /* Source address context based uncompression */
423 pr_debug("SAC bit is set. Handle context based source address.\n");
424 err = uncompress_context_based_src_addr(
425 skb, &hdr.saddr, tmp);
426 } else {
427 /* Source address uncompression */
428 pr_debug("source address stateless compression\n");
429 err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
430 saddr_type, saddr_len);
431 }
432
433 /* Check on error of previous branch */
434 if (err)
435 goto drop;
436
437 /* Extract DAM to the tmp variable */
438 tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
439
440 /* check for Multicast Compression */
441 if (iphc1 & LOWPAN_IPHC_M) {
442 if (iphc1 & LOWPAN_IPHC_DAC) {
443 pr_debug("dest: context-based mcast compression\n");
444 /* TODO: implement this */
445 } else {
446 err = lowpan_uncompress_multicast_daddr(
447 skb, &hdr.daddr, tmp);
448 if (err)
449 goto drop;
450 }
451 } else {
452 err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
453 daddr_type, daddr_len);
454 pr_debug("dest: stateless compression mode %d dest %pI6c\n",
455 tmp, &hdr.daddr);
456 if (err)
457 goto drop;
458 }
459
460 /* UDP data uncompression */
461 if (iphc0 & LOWPAN_IPHC_NH_C) {
462 struct udphdr uh;
463 struct sk_buff *new;
464
465 if (uncompress_udp_header(skb, &uh))
466 goto drop;
467
468 /* replace the compressed UDP head by the uncompressed UDP
469 * header
470 */
471 new = skb_copy_expand(skb, sizeof(struct udphdr),
472 skb_tailroom(skb), GFP_ATOMIC);
473 kfree_skb(skb);
474
475 if (!new)
476 return -ENOMEM;
477
478 skb = new;
479
480 skb_push(skb, sizeof(struct udphdr));
481 skb_reset_transport_header(skb);
482 skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
483
484 raw_dump_table(__func__, "raw UDP header dump",
485 (u8 *)&uh, sizeof(uh));
486
487 hdr.nexthdr = UIP_PROTO_UDP;
488 }
489
490 hdr.payload_len = htons(skb->len);
491
492 pr_debug("skb headroom size = %d, data length = %d\n",
493 skb_headroom(skb), skb->len);
494
495 pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t"
496 "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n",
497 hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
498 hdr.hop_limit, &hdr.daddr);
499
500 raw_dump_table(__func__, "raw header dump",
501 (u8 *)&hdr, sizeof(hdr));
502
503 return skb_deliver(skb, &hdr, dev, deliver_skb);
504
505drop:
506 kfree_skb(skb);
507 return -EINVAL;
508}
509EXPORT_SYMBOL_GPL(lowpan_process_data);
510
511static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
512 const struct in6_addr *ipaddr,
513 const unsigned char *lladdr)
514{
515 u8 val = 0;
516
517 if (is_addr_mac_addr_based(ipaddr, lladdr)) {
518 val = 3; /* 0-bits */
519 pr_debug("address compression 0 bits\n");
520 } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
521 /* compress IID to 16 bits xxxx::XXXX */
522 memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
523 *hc06_ptr += 2;
524 val = 2; /* 16-bits */
525 raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
526 *hc06_ptr - 2, 2);
527 } else {
528 /* do not compress IID => xxxx::IID */
529 memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
530 *hc06_ptr += 8;
531 val = 1; /* 64-bits */
532 raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
533 *hc06_ptr - 8, 8);
534 }
535
536 return rol8(val, shift);
537}
538
539static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
540{
541 struct udphdr *uh = udp_hdr(skb);
542 u8 tmp;
543
544 if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
545 LOWPAN_NHC_UDP_4BIT_PORT) &&
546 ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
547 LOWPAN_NHC_UDP_4BIT_PORT)) {
548 pr_debug("UDP header: both ports compression to 4 bits\n");
549 /* compression value */
550 tmp = LOWPAN_NHC_UDP_CS_P_11;
551 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
552 /* source and destination port */
553 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
554 ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
555 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
556 } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
557 LOWPAN_NHC_UDP_8BIT_PORT) {
558 pr_debug("UDP header: remove 8 bits of dest\n");
559 /* compression value */
560 tmp = LOWPAN_NHC_UDP_CS_P_01;
561 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
562 /* source port */
563 lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
564 /* destination port */
565 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
566 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
567 } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
568 LOWPAN_NHC_UDP_8BIT_PORT) {
569 pr_debug("UDP header: remove 8 bits of source\n");
570 /* compression value */
571 tmp = LOWPAN_NHC_UDP_CS_P_10;
572 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
573 /* source port */
574 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
575 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
576 /* destination port */
577 lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
578 } else {
579 pr_debug("UDP header: can't compress\n");
580 /* compression value */
581 tmp = LOWPAN_NHC_UDP_CS_P_00;
582 lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
583 /* source port */
584 lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
585 /* destination port */
586 lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
587 }
588
589 /* checksum is always inline */
590 lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check));
591
592 /* skip the UDP header */
593 skb_pull(skb, sizeof(struct udphdr));
594}
595
596int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
597 unsigned short type, const void *_daddr,
598 const void *_saddr, unsigned int len)
599{
600 u8 tmp, iphc0, iphc1, *hc06_ptr;
601 struct ipv6hdr *hdr;
602 u8 head[100] = {};
603
604 if (type != ETH_P_IPV6)
605 return -EINVAL;
606
607 hdr = ipv6_hdr(skb);
608 hc06_ptr = head + 2;
609
610 pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n"
611 "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n",
612 hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
613 hdr->hop_limit, &hdr->daddr);
614
615 raw_dump_table(__func__, "raw skb network header dump",
616 skb_network_header(skb), sizeof(struct ipv6hdr));
617
618 /* As we copy some bit-length fields, in the IPHC encoding bytes,
619 * we sometimes use |=
620 * If the field is 0, and the current bit value in memory is 1,
621 * this does not work. We therefore reset the IPHC encoding here
622 */
623 iphc0 = LOWPAN_DISPATCH_IPHC;
624 iphc1 = 0;
625
626 /* TODO: context lookup */
627
628 raw_dump_inline(__func__, "saddr",
629 (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
630 raw_dump_inline(__func__, "daddr",
631 (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
632
633 raw_dump_table(__func__,
634 "sending raw skb network uncompressed packet",
635 skb->data, skb->len);
636
637 /* Traffic class, flow label
638 * If flow label is 0, compress it. If traffic class is 0, compress it
639 * We have to process both in the same time as the offset of traffic
640 * class depends on the presence of version and flow label
641 */
642
643 /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
644 tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
645 tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
646
647 if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
648 (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
649 /* flow label can be compressed */
650 iphc0 |= LOWPAN_IPHC_FL_C;
651 if ((hdr->priority == 0) &&
652 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
653 /* compress (elide) all */
654 iphc0 |= LOWPAN_IPHC_TC_C;
655 } else {
656 /* compress only the flow label */
657 *hc06_ptr = tmp;
658 hc06_ptr += 1;
659 }
660 } else {
661 /* Flow label cannot be compressed */
662 if ((hdr->priority == 0) &&
663 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
664 /* compress only traffic class */
665 iphc0 |= LOWPAN_IPHC_TC_C;
666 *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
667 memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
668 hc06_ptr += 3;
669 } else {
670 /* compress nothing */
671 memcpy(hc06_ptr, hdr, 4);
672 /* replace the top byte with new ECN | DSCP format */
673 *hc06_ptr = tmp;
674 hc06_ptr += 4;
675 }
676 }
677
678 /* NOTE: payload length is always compressed */
679
680 /* Next Header is compress if UDP */
681 if (hdr->nexthdr == UIP_PROTO_UDP)
682 iphc0 |= LOWPAN_IPHC_NH_C;
683
684 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
685 *hc06_ptr = hdr->nexthdr;
686 hc06_ptr += 1;
687 }
688
689 /* Hop limit
690 * if 1: compress, encoding is 01
691 * if 64: compress, encoding is 10
692 * if 255: compress, encoding is 11
693 * else do not compress
694 */
695 switch (hdr->hop_limit) {
696 case 1:
697 iphc0 |= LOWPAN_IPHC_TTL_1;
698 break;
699 case 64:
700 iphc0 |= LOWPAN_IPHC_TTL_64;
701 break;
702 case 255:
703 iphc0 |= LOWPAN_IPHC_TTL_255;
704 break;
705 default:
706 *hc06_ptr = hdr->hop_limit;
707 hc06_ptr += 1;
708 break;
709 }
710
711 /* source address compression */
712 if (is_addr_unspecified(&hdr->saddr)) {
713 pr_debug("source address is unspecified, setting SAC\n");
714 iphc1 |= LOWPAN_IPHC_SAC;
715 /* TODO: context lookup */
716 } else if (is_addr_link_local(&hdr->saddr)) {
717 iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
718 LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr);
719 pr_debug("source address unicast link-local %pI6c "
720 "iphc1 0x%02x\n", &hdr->saddr, iphc1);
721 } else {
722 pr_debug("send the full source address\n");
723 memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
724 hc06_ptr += 16;
725 }
726
727 /* destination address compression */
728 if (is_addr_mcast(&hdr->daddr)) {
729 pr_debug("destination address is multicast: ");
730 iphc1 |= LOWPAN_IPHC_M;
731 if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
732 pr_debug("compressed to 1 octet\n");
733 iphc1 |= LOWPAN_IPHC_DAM_11;
734 /* use last byte */
735 *hc06_ptr = hdr->daddr.s6_addr[15];
736 hc06_ptr += 1;
737 } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
738 pr_debug("compressed to 4 octets\n");
739 iphc1 |= LOWPAN_IPHC_DAM_10;
740 /* second byte + the last three */
741 *hc06_ptr = hdr->daddr.s6_addr[1];
742 memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
743 hc06_ptr += 4;
744 } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
745 pr_debug("compressed to 6 octets\n");
746 iphc1 |= LOWPAN_IPHC_DAM_01;
747 /* second byte + the last five */
748 *hc06_ptr = hdr->daddr.s6_addr[1];
749 memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
750 hc06_ptr += 6;
751 } else {
752 pr_debug("using full address\n");
753 iphc1 |= LOWPAN_IPHC_DAM_00;
754 memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
755 hc06_ptr += 16;
756 }
757 } else {
758 /* TODO: context lookup */
759 if (is_addr_link_local(&hdr->daddr)) {
760 iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
761 LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
762 pr_debug("dest address unicast link-local %pI6c "
763 "iphc1 0x%02x\n", &hdr->daddr, iphc1);
764 } else {
765 pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
766 memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
767 hc06_ptr += 16;
768 }
769 }
770
771 /* UDP header compression */
772 if (hdr->nexthdr == UIP_PROTO_UDP)
773 compress_udp_header(&hc06_ptr, skb);
774
775 head[0] = iphc0;
776 head[1] = iphc1;
777
778 skb_pull(skb, sizeof(struct ipv6hdr));
779 skb_reset_transport_header(skb);
780 memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
781 skb_reset_network_header(skb);
782
783 pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len);
784
785 raw_dump_table(__func__, "raw skb data dump compressed",
786 skb->data, skb->len);
787 return 0;
788}
789EXPORT_SYMBOL_GPL(lowpan_header_compress);
790
791MODULE_LICENSE("GPL");