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