iphc.c 17.3 KB
Newer Older
1 2 3 4 5
/*
 * Copyright 2011, Siemens AG
 * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
 */

6
/* Based on patches from Jon Smirl <jonsmirl@gmail.com>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
 * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

/* Jon's code is based on 6lowpan implementation for Contiki which is:
 * Copyright (c) 2008, Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <linux/bitops.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
52
#include <net/6lowpan.h>
53 54 55
#include <net/ipv6.h>
#include <net/af_ieee802154.h>

56 57
#include "nhc.h"

58
/* Uncompress address function for source and
59 60 61 62 63
 * destination address(non-multicast).
 *
 * address_mode is sam value or dam value.
 */
static int uncompress_addr(struct sk_buff *skb,
64 65 66
			   struct in6_addr *ipaddr, const u8 address_mode,
			   const u8 *lladdr, const u8 addr_type,
			   const u8 addr_len)
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
{
	bool fail;

	switch (address_mode) {
	case LOWPAN_IPHC_ADDR_00:
		/* for global link addresses */
		fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
		break;
	case LOWPAN_IPHC_ADDR_01:
		/* fe:80::XXXX:XXXX:XXXX:XXXX */
		ipaddr->s6_addr[0] = 0xFE;
		ipaddr->s6_addr[1] = 0x80;
		fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
		break;
	case LOWPAN_IPHC_ADDR_02:
		/* fe:80::ff:fe00:XXXX */
		ipaddr->s6_addr[0] = 0xFE;
		ipaddr->s6_addr[1] = 0x80;
		ipaddr->s6_addr[11] = 0xFF;
		ipaddr->s6_addr[12] = 0xFE;
		fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
		break;
	case LOWPAN_IPHC_ADDR_03:
		fail = false;
		switch (addr_type) {
		case IEEE802154_ADDR_LONG:
			/* fe:80::XXXX:XXXX:XXXX:XXXX
			 *        \_________________/
			 *              hwaddr
			 */
			ipaddr->s6_addr[0] = 0xFE;
			ipaddr->s6_addr[1] = 0x80;
			memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
			/* second bit-flip (Universe/Local)
			 * is done according RFC2464
			 */
			ipaddr->s6_addr[8] ^= 0x02;
			break;
		case IEEE802154_ADDR_SHORT:
			/* fe:80::ff:fe00:XXXX
			 *		  \__/
			 *	       short_addr
			 *
			 * Universe/Local bit is zero.
			 */
			ipaddr->s6_addr[0] = 0xFE;
			ipaddr->s6_addr[1] = 0x80;
			ipaddr->s6_addr[11] = 0xFF;
			ipaddr->s6_addr[12] = 0xFE;
			ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
			break;
		default:
			pr_debug("Invalid addr_type set\n");
			return -EINVAL;
		}
		break;
	default:
		pr_debug("Invalid address mode value: 0x%x\n", address_mode);
		return -EINVAL;
	}

	if (fail) {
		pr_debug("Failed to fetch skb data\n");
		return -EIO;
	}

	raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
			ipaddr->s6_addr, 16);

	return 0;
}

139
/* Uncompress address function for source context
140 141 142
 * based address(non-multicast).
 */
static int uncompress_context_based_src_addr(struct sk_buff *skb,
143 144
					     struct in6_addr *ipaddr,
					     const u8 sam)
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
{
	switch (sam) {
	case LOWPAN_IPHC_ADDR_00:
		/* unspec address ::
		 * Do nothing, address is already ::
		 */
		break;
	case LOWPAN_IPHC_ADDR_01:
		/* TODO */
	case LOWPAN_IPHC_ADDR_02:
		/* TODO */
	case LOWPAN_IPHC_ADDR_03:
		/* TODO */
		netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
		return -EINVAL;
	default:
		pr_debug("Invalid sam value: 0x%x\n", sam);
		return -EINVAL;
	}

	raw_dump_inline(NULL,
			"Reconstructed context based ipv6 src addr is",
			ipaddr->s6_addr, 16);

	return 0;
}

/* Uncompress function for multicast destination address,
 * when M bit is set.
 */
175 176 177
static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
					     struct in6_addr *ipaddr,
					     const u8 dam)
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
{
	bool fail;

	switch (dam) {
	case LOWPAN_IPHC_DAM_00:
		/* 00:  128 bits.  The full address
		 * is carried in-line.
		 */
		fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
		break;
	case LOWPAN_IPHC_DAM_01:
		/* 01:  48 bits.  The address takes
		 * the form ffXX::00XX:XXXX:XXXX.
		 */
		ipaddr->s6_addr[0] = 0xFF;
		fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
		fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
		break;
	case LOWPAN_IPHC_DAM_10:
		/* 10:  32 bits.  The address takes
		 * the form ffXX::00XX:XXXX.
		 */
		ipaddr->s6_addr[0] = 0xFF;
		fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
		fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
		break;
	case LOWPAN_IPHC_DAM_11:
		/* 11:  8 bits.  The address takes
		 * the form ff02::00XX.
		 */
		ipaddr->s6_addr[0] = 0xFF;
		ipaddr->s6_addr[1] = 0x02;
		fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
		break;
	default:
		pr_debug("DAM value has a wrong value: 0x%x\n", dam);
		return -EINVAL;
	}

	if (fail) {
		pr_debug("Failed to fetch skb data\n");
		return -EIO;
	}

	raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
223
			ipaddr->s6_addr, 16);
224 225 226 227 228 229 230

	return 0;
}

/* TTL uncompression values */
static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };

231 232 233 234 235 236
int
lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
			 const u8 *saddr, const u8 saddr_type,
			 const u8 saddr_len, const u8 *daddr,
			 const u8 daddr_type, const u8 daddr_len,
			 u8 iphc0, u8 iphc1)
237 238 239 240 241 242
{
	struct ipv6hdr hdr = {};
	u8 tmp, num_context = 0;
	int err;

	raw_dump_table(__func__, "raw skb data dump uncompressed",
243
		       skb->data, skb->len);
244 245 246 247

	/* another if the CID flag is set */
	if (iphc1 & LOWPAN_IPHC_CID) {
		pr_debug("CID flag is set, increase header with one\n");
248
		if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
249
			return -EINVAL;
250 251 252 253 254 255
	}

	hdr.version = 6;

	/* Traffic Class and Flow Label */
	switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
256
	/* Traffic Class and FLow Label carried in-line
257 258 259
	 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
	 */
	case 0: /* 00b */
260
		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
261
			return -EINVAL;
262 263 264 265 266 267 268

		memcpy(&hdr.flow_lbl, &skb->data[0], 3);
		skb_pull(skb, 3);
		hdr.priority = ((tmp >> 2) & 0x0f);
		hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
					(hdr.flow_lbl[0] & 0x0f);
		break;
269
	/* Traffic class carried in-line
270 271 272
	 * ECN + DSCP (1 byte), Flow Label is elided
	 */
	case 2: /* 10b */
273
		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
274
			return -EINVAL;
275 276 277 278

		hdr.priority = ((tmp >> 2) & 0x0f);
		hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
		break;
279
	/* Flow Label carried in-line
280 281 282
	 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
	 */
	case 1: /* 01b */
283
		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
284
			return -EINVAL;
285

286
		hdr.flow_lbl[0] = (tmp & 0x0F) | ((tmp >> 2) & 0x30);
287 288 289 290 291 292 293 294 295 296 297 298 299
		memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
		skb_pull(skb, 2);
		break;
	/* Traffic Class and Flow Label are elided */
	case 3: /* 11b */
		break;
	default:
		break;
	}

	/* Next Header */
	if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
		/* Next header is carried inline */
300
		if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
301
			return -EINVAL;
302 303 304 305 306 307

		pr_debug("NH flag is set, next header carried inline: %02x\n",
			 hdr.nexthdr);
	}

	/* Hop Limit */
308
	if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
309
		hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
310
	} else {
311 312
		if (lowpan_fetch_skb(skb, &hdr.hop_limit,
				     sizeof(hdr.hop_limit)))
313
			return -EINVAL;
314 315 316 317 318 319 320 321
	}

	/* Extract SAM to the tmp variable */
	tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;

	if (iphc1 & LOWPAN_IPHC_SAC) {
		/* Source address context based uncompression */
		pr_debug("SAC bit is set. Handle context based source address.\n");
322
		err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp);
323 324 325 326
	} else {
		/* Source address uncompression */
		pr_debug("source address stateless compression\n");
		err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
327
				      saddr_type, saddr_len);
328 329 330 331
	}

	/* Check on error of previous branch */
	if (err)
332
		return -EINVAL;
333 334 335 336 337 338 339 340 341 342

	/* Extract DAM to the tmp variable */
	tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;

	/* check for Multicast Compression */
	if (iphc1 & LOWPAN_IPHC_M) {
		if (iphc1 & LOWPAN_IPHC_DAC) {
			pr_debug("dest: context-based mcast compression\n");
			/* TODO: implement this */
		} else {
343 344 345
			err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
								tmp);

346
			if (err)
347
				return -EINVAL;
348 349 350
		}
	} else {
		err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
351
				      daddr_type, daddr_len);
352
		pr_debug("dest: stateless compression mode %d dest %pI6c\n",
353
			 tmp, &hdr.daddr);
354
		if (err)
355
			return -EINVAL;
356 357
	}

358
	/* Next header data uncompression */
359
	if (iphc0 & LOWPAN_IPHC_NH_C) {
360 361
		err = lowpan_nhc_do_uncompression(skb, dev, &hdr);
		if (err < 0)
362 363 364
			return err;
	} else {
		err = skb_cow(skb, sizeof(hdr));
365
		if (unlikely(err))
366
			return err;
367 368 369 370 371 372 373 374 375 376 377 378
	}

	hdr.payload_len = htons(skb->len);

	pr_debug("skb headroom size = %d, data length = %d\n",
		 skb_headroom(skb), skb->len);

	pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
		 "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
		hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
		hdr.hop_limit, &hdr.daddr);

379 380 381
	skb_push(skb, sizeof(hdr));
	skb_reset_network_header(skb);
	skb_copy_to_linear_data(skb, &hdr, sizeof(hdr));
382

383
	raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
384

385
	return 0;
386
}
387
EXPORT_SYMBOL_GPL(lowpan_header_decompress);
388

389
static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
390 391
				  const struct in6_addr *ipaddr,
				  const unsigned char *lladdr)
392 393 394 395 396 397 398 399
{
	u8 val = 0;

	if (is_addr_mac_addr_based(ipaddr, lladdr)) {
		val = 3; /* 0-bits */
		pr_debug("address compression 0 bits\n");
	} else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
		/* compress IID to 16 bits xxxx::XXXX */
400
		lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
401 402
		val = 2; /* 16-bits */
		raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
403
				*hc_ptr - 2, 2);
404 405
	} else {
		/* do not compress IID => xxxx::IID */
406
		lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
407 408
		val = 1; /* 64-bits */
		raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
409
				*hc_ptr - 8, 8);
410 411 412 413 414 415
	}

	return rol8(val, shift);
}

int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
416 417
			   unsigned short type, const void *_daddr,
			   const void *_saddr, unsigned int len)
418
{
419
	u8 tmp, iphc0, iphc1, *hc_ptr;
420 421
	struct ipv6hdr *hdr;
	u8 head[100] = {};
422
	int ret, addr_type;
423 424 425 426 427

	if (type != ETH_P_IPV6)
		return -EINVAL;

	hdr = ipv6_hdr(skb);
428
	hc_ptr = head + 2;
429 430 431

	pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
		 "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
432 433
		 hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
		 hdr->hop_limit, &hdr->daddr);
434 435

	raw_dump_table(__func__, "raw skb network header dump",
436
		       skb_network_header(skb), sizeof(struct ipv6hdr));
437

438
	/* As we copy some bit-length fields, in the IPHC encoding bytes,
439 440 441 442 443 444 445 446 447 448 449 450 451 452
	 * we sometimes use |=
	 * If the field is 0, and the current bit value in memory is 1,
	 * this does not work. We therefore reset the IPHC encoding here
	 */
	iphc0 = LOWPAN_DISPATCH_IPHC;
	iphc1 = 0;

	/* TODO: context lookup */

	raw_dump_inline(__func__, "saddr",
			(unsigned char *)_saddr, IEEE802154_ADDR_LEN);
	raw_dump_inline(__func__, "daddr",
			(unsigned char *)_daddr, IEEE802154_ADDR_LEN);

453
	raw_dump_table(__func__, "sending raw skb network uncompressed packet",
454
		       skb->data, skb->len);
455

456
	/* Traffic class, flow label
457 458 459 460 461
	 * If flow label is 0, compress it. If traffic class is 0, compress it
	 * We have to process both in the same time as the offset of traffic
	 * class depends on the presence of version and flow label
	 */

462
	/* hc format of TC is ECN | DSCP , original one is DSCP | ECN */
463 464 465 466
	tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
	tmp = ((tmp & 0x03) << 6) | (tmp >> 2);

	if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
467
	    (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
468 469 470
		/* flow label can be compressed */
		iphc0 |= LOWPAN_IPHC_FL_C;
		if ((hdr->priority == 0) &&
471
		    ((hdr->flow_lbl[0] & 0xF0) == 0)) {
472 473 474 475
			/* compress (elide) all */
			iphc0 |= LOWPAN_IPHC_TC_C;
		} else {
			/* compress only the flow label */
476 477
			*hc_ptr = tmp;
			hc_ptr += 1;
478 479 480 481
		}
	} else {
		/* Flow label cannot be compressed */
		if ((hdr->priority == 0) &&
482
		    ((hdr->flow_lbl[0] & 0xF0) == 0)) {
483 484
			/* compress only traffic class */
			iphc0 |= LOWPAN_IPHC_TC_C;
485 486 487
			*hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
			memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
			hc_ptr += 3;
488 489
		} else {
			/* compress nothing */
490
			memcpy(hc_ptr, hdr, 4);
491
			/* replace the top byte with new ECN | DSCP format */
492 493
			*hc_ptr = tmp;
			hc_ptr += 4;
494 495 496 497 498
		}
	}

	/* NOTE: payload length is always compressed */

499 500 501 502 503 504
	/* Check if we provide the nhc format for nexthdr and compression
	 * functionality. If not nexthdr is handled inline and not compressed.
	 */
	ret = lowpan_nhc_check_compression(skb, hdr, &hc_ptr, &iphc0);
	if (ret < 0)
		return ret;
505

506
	/* Hop limit
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
	 * if 1:   compress, encoding is 01
	 * if 64:  compress, encoding is 10
	 * if 255: compress, encoding is 11
	 * else do not compress
	 */
	switch (hdr->hop_limit) {
	case 1:
		iphc0 |= LOWPAN_IPHC_TTL_1;
		break;
	case 64:
		iphc0 |= LOWPAN_IPHC_TTL_64;
		break;
	case 255:
		iphc0 |= LOWPAN_IPHC_TTL_255;
		break;
	default:
523 524
		lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit,
				    sizeof(hdr->hop_limit));
525 526
	}

527
	addr_type = ipv6_addr_type(&hdr->saddr);
528
	/* source address compression */
529
	if (addr_type == IPV6_ADDR_ANY) {
530 531 532
		pr_debug("source address is unspecified, setting SAC\n");
		iphc1 |= LOWPAN_IPHC_SAC;
	} else {
533 534 535 536 537 538 539 540 541 542
		if (addr_type & IPV6_ADDR_LINKLOCAL) {
			iphc1 |= lowpan_compress_addr_64(&hc_ptr,
							 LOWPAN_IPHC_SAM_BIT,
							 &hdr->saddr, _saddr);
			pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
				 &hdr->saddr, iphc1);
		} else {
			pr_debug("send the full source address\n");
			lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16);
		}
543 544
	}

545
	addr_type = ipv6_addr_type(&hdr->daddr);
546
	/* destination address compression */
547
	if (addr_type & IPV6_ADDR_MULTICAST) {
548 549 550 551 552 553
		pr_debug("destination address is multicast: ");
		iphc1 |= LOWPAN_IPHC_M;
		if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
			pr_debug("compressed to 1 octet\n");
			iphc1 |= LOWPAN_IPHC_DAM_11;
			/* use last byte */
554 555
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[15], 1);
556 557 558 559
		} else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
			pr_debug("compressed to 4 octets\n");
			iphc1 |= LOWPAN_IPHC_DAM_10;
			/* second byte + the last three */
560 561 562 563
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[1], 1);
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[13], 3);
564 565 566 567
		} else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
			pr_debug("compressed to 6 octets\n");
			iphc1 |= LOWPAN_IPHC_DAM_01;
			/* second byte + the last five */
568 569 570 571
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[1], 1);
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[11], 5);
572 573 574
		} else {
			pr_debug("using full address\n");
			iphc1 |= LOWPAN_IPHC_DAM_00;
575
			lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
576 577
		}
	} else {
578 579
		if (addr_type & IPV6_ADDR_LINKLOCAL) {
			/* TODO: context lookup */
580
			iphc1 |= lowpan_compress_addr_64(&hc_ptr,
581 582
				LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
			pr_debug("dest address unicast link-local %pI6c "
583
				 "iphc1 0x%02x\n", &hdr->daddr, iphc1);
584 585
		} else {
			pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
586
			lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
587 588 589
		}
	}

590 591 592 593 594 595
	/* next header compression */
	if (iphc0 & LOWPAN_IPHC_NH_C) {
		ret = lowpan_nhc_do_compression(skb, hdr, &hc_ptr);
		if (ret < 0)
			return ret;
	}
596 597 598 599 600 601

	head[0] = iphc0;
	head[1] = iphc1;

	skb_pull(skb, sizeof(struct ipv6hdr));
	skb_reset_transport_header(skb);
602
	memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head);
603 604
	skb_reset_network_header(skb);

605
	pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len);
606 607

	raw_dump_table(__func__, "raw skb data dump compressed",
608
		       skb->data, skb->len);
609 610 611
	return 0;
}
EXPORT_SYMBOL_GPL(lowpan_header_compress);