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