iphc.c 22.4 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 52 53
 * 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.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/* 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>
54
#include <linux/module.h>
55
#include <linux/netdevice.h>
56
#include <net/6lowpan.h>
57 58 59
#include <net/ipv6.h>
#include <net/af_ieee802154.h>

60
/* Uncompress address function for source and
61 62 63 64 65
 * destination address(non-multicast).
 *
 * address_mode is sam value or dam value.
 */
static int uncompress_addr(struct sk_buff *skb,
66 67 68
			   struct in6_addr *ipaddr, const u8 address_mode,
			   const u8 *lladdr, const u8 addr_type,
			   const u8 addr_len)
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 139 140
{
	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;
}

141
/* Uncompress address function for source context
142 143 144
 * based address(non-multicast).
 */
static int uncompress_context_based_src_addr(struct sk_buff *skb,
145 146
					     struct in6_addr *ipaddr,
					     const u8 sam)
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;
}

static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
175
		       struct net_device *dev, skb_delivery_cb deliver_skb)
176 177 178 179 180
{
	struct sk_buff *new;
	int stat;

	new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
181
			      GFP_ATOMIC);
182 183 184 185 186 187 188 189 190 191 192 193 194 195
	kfree_skb(skb);

	if (!new)
		return -ENOMEM;

	skb_push(new, sizeof(struct ipv6hdr));
	skb_reset_network_header(new);
	skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));

	new->protocol = htons(ETH_P_IPV6);
	new->pkt_type = PACKET_HOST;
	new->dev = dev;

	raw_dump_table(__func__, "raw skb data dump before receiving",
196
		       new->data, new->len);
197 198 199 200 201 202 203 204 205 206 207

	stat = deliver_skb(new, dev);

	kfree_skb(new);

	return stat;
}

/* Uncompress function for multicast destination address,
 * when M bit is set.
 */
208 209 210
static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
					     struct in6_addr *ipaddr,
					     const u8 dam)
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
{
	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",
256
			ipaddr->s6_addr, 16);
257 258 259 260

	return 0;
}

261
static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
262
{
263 264
	bool fail;
	u8 tmp = 0, val = 0;
265

266
	fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
267 268 269 270 271

	if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
		pr_debug("UDP header uncompression\n");
		switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
		case LOWPAN_NHC_UDP_CS_P_00:
272 273 274 275
			fail |= lowpan_fetch_skb(skb, &uh->source,
						 sizeof(uh->source));
			fail |= lowpan_fetch_skb(skb, &uh->dest,
						 sizeof(uh->dest));
276 277
			break;
		case LOWPAN_NHC_UDP_CS_P_01:
278 279 280
			fail |= lowpan_fetch_skb(skb, &uh->source,
						 sizeof(uh->source));
			fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
281
			uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
282 283
			break;
		case LOWPAN_NHC_UDP_CS_P_10:
284
			fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
285
			uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
286 287
			fail |= lowpan_fetch_skb(skb, &uh->dest,
						 sizeof(uh->dest));
288 289
			break;
		case LOWPAN_NHC_UDP_CS_P_11:
290
			fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
A
Alexander Aring 已提交
291
			uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
292
					   (val >> 4));
A
Alexander Aring 已提交
293
			uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
294
					 (val & 0x0f));
295 296 297 298 299 300 301 302
			break;
		default:
			pr_debug("ERROR: unknown UDP format\n");
			goto err;
			break;
		}

		pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
A
Alexander Aring 已提交
303
			 ntohs(uh->source), ntohs(uh->dest));
304

305 306 307 308 309
		/* checksum */
		if (tmp & LOWPAN_NHC_UDP_CS_C) {
			pr_debug_ratelimited("checksum elided currently not supported\n");
			goto err;
		} else {
310 311
			fail |= lowpan_fetch_skb(skb, &uh->check,
						 sizeof(uh->check));
312
		}
313

314
		/* UDP length needs to be infered from the lower layers
315 316 317 318
		 * here, we obtain the hint from the remaining size of the
		 * frame
		 */
		uh->len = htons(skb->len + sizeof(struct udphdr));
A
Alexander Aring 已提交
319
		pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
320 321 322 323 324
	} else {
		pr_debug("ERROR: unsupported NH format\n");
		goto err;
	}

325 326 327
	if (fail)
		goto err;

328 329 330 331 332 333 334 335 336
	return 0;
err:
	return -EINVAL;
}

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

int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
337 338 339
			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, skb_delivery_cb deliver_skb)
340 341 342 343 344 345
{
	struct ipv6hdr hdr = {};
	u8 tmp, num_context = 0;
	int err;

	raw_dump_table(__func__, "raw skb data dump uncompressed",
346
		       skb->data, skb->len);
347 348 349 350

	/* another if the CID flag is set */
	if (iphc1 & LOWPAN_IPHC_CID) {
		pr_debug("CID flag is set, increase header with one\n");
351
		if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
352 353 354 355 356 357 358
			goto drop;
	}

	hdr.version = 6;

	/* Traffic Class and Flow Label */
	switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
359
	/* Traffic Class and FLow Label carried in-line
360 361 362
	 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
	 */
	case 0: /* 00b */
363
		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
364 365 366 367 368 369 370 371
			goto drop;

		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;
372
	/* Traffic class carried in-line
373 374 375
	 * ECN + DSCP (1 byte), Flow Label is elided
	 */
	case 2: /* 10b */
376
		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
377 378 379 380 381
			goto drop;

		hdr.priority = ((tmp >> 2) & 0x0f);
		hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
		break;
382
	/* Flow Label carried in-line
383 384 385
	 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
	 */
	case 1: /* 01b */
386
		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
			goto drop;

		hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
		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 */
403
		if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
404 405 406 407 408 409 410 411 412 413
			goto drop;

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

	/* Hop Limit */
	if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
		hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
	else {
414 415
		if (lowpan_fetch_skb(skb, &hdr.hop_limit,
				     sizeof(hdr.hop_limit)))
416 417 418 419 420 421 422 423 424
			goto drop;
	}

	/* 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");
425
		err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp);
426 427 428 429
	} else {
		/* Source address uncompression */
		pr_debug("source address stateless compression\n");
		err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
430
				      saddr_type, saddr_len);
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
	}

	/* Check on error of previous branch */
	if (err)
		goto drop;

	/* 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 {
446 447 448
			err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
								tmp);

449 450 451 452 453
			if (err)
				goto drop;
		}
	} else {
		err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
454
				      daddr_type, daddr_len);
455
		pr_debug("dest: stateless compression mode %d dest %pI6c\n",
456
			 tmp, &hdr.daddr);
457 458 459 460 461 462 463 464
		if (err)
			goto drop;
	}

	/* UDP data uncompression */
	if (iphc0 & LOWPAN_IPHC_NH_C) {
		struct udphdr uh;
		struct sk_buff *new;
465

466 467 468
		if (uncompress_udp_header(skb, &uh))
			goto drop;

469
		/* replace the compressed UDP head by the uncompressed UDP
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
		 * header
		 */
		new = skb_copy_expand(skb, sizeof(struct udphdr),
				      skb_tailroom(skb), GFP_ATOMIC);
		kfree_skb(skb);

		if (!new)
			return -ENOMEM;

		skb = new;

		skb_push(skb, sizeof(struct udphdr));
		skb_reset_transport_header(skb);
		skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));

		raw_dump_table(__func__, "raw UDP header dump",
486
			       (u8 *)&uh, sizeof(uh));
487 488 489 490 491 492 493 494 495 496 497 498 499 500

		hdr.nexthdr = UIP_PROTO_UDP;
	}

	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);

501
	raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
502 503 504 505 506 507 508 509 510

	return skb_deliver(skb, &hdr, dev, deliver_skb);

drop:
	kfree_skb(skb);
	return -EINVAL;
}
EXPORT_SYMBOL_GPL(lowpan_process_data);

511 512 513
static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
				  const struct in6_addr *ipaddr,
				  const unsigned char *lladdr)
514 515 516 517 518 519 520 521
{
	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 */
522
		lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
523 524
		val = 2; /* 16-bits */
		raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
525
				*hc_ptr - 2, 2);
526 527
	} else {
		/* do not compress IID => xxxx::IID */
528
		lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
529 530
		val = 1; /* 64-bits */
		raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
531
				*hc_ptr - 8, 8);
532 533 534 535 536
	}

	return rol8(val, shift);
}

537
static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
538 539
{
	struct udphdr *uh = udp_hdr(skb);
540
	u8 tmp;
541

A
Alexander Aring 已提交
542 543 544 545
	if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
	     LOWPAN_NHC_UDP_4BIT_PORT) &&
	    ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
	     LOWPAN_NHC_UDP_4BIT_PORT)) {
546
		pr_debug("UDP header: both ports compression to 4 bits\n");
547
		/* compression value */
548
		tmp = LOWPAN_NHC_UDP_CS_P_11;
549
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
550 551 552
		/* source and destination port */
		tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
		      ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
553
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
A
Alexander Aring 已提交
554
	} else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
555 556
			LOWPAN_NHC_UDP_8BIT_PORT) {
		pr_debug("UDP header: remove 8 bits of dest\n");
557
		/* compression value */
558
		tmp = LOWPAN_NHC_UDP_CS_P_01;
559
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
560
		/* source port */
561
		lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
562 563
		/* destination port */
		tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
564
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
A
Alexander Aring 已提交
565
	} else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
566 567
			LOWPAN_NHC_UDP_8BIT_PORT) {
		pr_debug("UDP header: remove 8 bits of source\n");
568
		/* compression value */
569
		tmp = LOWPAN_NHC_UDP_CS_P_10;
570
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
571 572
		/* source port */
		tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
573
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
574
		/* destination port */
575
		lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
576 577
	} else {
		pr_debug("UDP header: can't compress\n");
578
		/* compression value */
579
		tmp = LOWPAN_NHC_UDP_CS_P_00;
580
		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
581
		/* source port */
582
		lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
583
		/* destination port */
584
		lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
585 586 587
	}

	/* checksum is always inline */
588
	lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
589 590 591 592 593 594

	/* skip the UDP header */
	skb_pull(skb, sizeof(struct udphdr));
}

int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
595 596
			   unsigned short type, const void *_daddr,
			   const void *_saddr, unsigned int len)
597
{
598
	u8 tmp, iphc0, iphc1, *hc_ptr;
599 600
	struct ipv6hdr *hdr;
	u8 head[100] = {};
601
	int addr_type;
602 603 604 605 606

	if (type != ETH_P_IPV6)
		return -EINVAL;

	hdr = ipv6_hdr(skb);
607
	hc_ptr = head + 2;
608 609 610

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

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

617
	/* As we copy some bit-length fields, in the IPHC encoding bytes,
618 619 620 621 622 623 624 625 626 627 628 629 630 631
	 * 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);

632 633
	raw_dump_table(__func__, "sending raw skb network uncompressed packet",
		       skb->data, skb->len);
634

635
	/* Traffic class, flow label
636 637 638 639 640
	 * 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
	 */

641
	/* hc format of TC is ECN | DSCP , original one is DSCP | ECN */
642 643 644 645 646 647 648 649 650 651 652 653 654
	tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
	tmp = ((tmp & 0x03) << 6) | (tmp >> 2);

	if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
	     (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
		/* flow label can be compressed */
		iphc0 |= LOWPAN_IPHC_FL_C;
		if ((hdr->priority == 0) &&
		   ((hdr->flow_lbl[0] & 0xF0) == 0)) {
			/* compress (elide) all */
			iphc0 |= LOWPAN_IPHC_TC_C;
		} else {
			/* compress only the flow label */
655 656
			*hc_ptr = tmp;
			hc_ptr += 1;
657 658 659 660 661 662 663
		}
	} else {
		/* Flow label cannot be compressed */
		if ((hdr->priority == 0) &&
		   ((hdr->flow_lbl[0] & 0xF0) == 0)) {
			/* compress only traffic class */
			iphc0 |= LOWPAN_IPHC_TC_C;
664 665 666
			*hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
			memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
			hc_ptr += 3;
667 668
		} else {
			/* compress nothing */
669
			memcpy(hc_ptr, hdr, 4);
670
			/* replace the top byte with new ECN | DSCP format */
671 672
			*hc_ptr = tmp;
			hc_ptr += 4;
673 674 675 676 677 678 679 680 681
		}
	}

	/* NOTE: payload length is always compressed */

	/* Next Header is compress if UDP */
	if (hdr->nexthdr == UIP_PROTO_UDP)
		iphc0 |= LOWPAN_IPHC_NH_C;

682 683 684
	if ((iphc0 & LOWPAN_IPHC_NH_C) == 0)
		lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr,
				    sizeof(hdr->nexthdr));
685

686
	/* Hop limit
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
	 * 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:
703 704
		lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit,
				    sizeof(hdr->hop_limit));
705 706
	}

707
	addr_type = ipv6_addr_type(&hdr->saddr);
708
	/* source address compression */
709
	if (addr_type == IPV6_ADDR_ANY) {
710 711 712
		pr_debug("source address is unspecified, setting SAC\n");
		iphc1 |= LOWPAN_IPHC_SAC;
	} else {
713 714 715 716 717 718 719 720 721 722
		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);
		}
723 724
	}

725
	addr_type = ipv6_addr_type(&hdr->daddr);
726
	/* destination address compression */
727
	if (addr_type & IPV6_ADDR_MULTICAST) {
728 729 730 731 732 733
		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 */
734 735
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[15], 1);
736 737 738 739
		} 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 */
740 741 742 743
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[1], 1);
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[13], 3);
744 745 746 747
		} 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 */
748 749 750 751
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[1], 1);
			lowpan_push_hc_data(&hc_ptr,
					    &hdr->daddr.s6_addr[11], 5);
752 753 754
		} else {
			pr_debug("using full address\n");
			iphc1 |= LOWPAN_IPHC_DAM_00;
755
			lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
756 757
		}
	} else {
758 759
		if (addr_type & IPV6_ADDR_LINKLOCAL) {
			/* TODO: context lookup */
760
			iphc1 |= lowpan_compress_addr_64(&hc_ptr,
761 762
				LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
			pr_debug("dest address unicast link-local %pI6c "
763
				 "iphc1 0x%02x\n", &hdr->daddr, iphc1);
764 765
		} else {
			pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
766
			lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
767 768 769 770 771
		}
	}

	/* UDP header compression */
	if (hdr->nexthdr == UIP_PROTO_UDP)
772
		compress_udp_header(&hc_ptr, skb);
773 774 775 776 777 778

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

	skb_pull(skb, sizeof(struct ipv6hdr));
	skb_reset_transport_header(skb);
779
	memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head);
780 781
	skb_reset_network_header(skb);

782
	pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len);
783 784

	raw_dump_table(__func__, "raw skb data dump compressed",
785
		       skb->data, skb->len);
786 787 788
	return 0;
}
EXPORT_SYMBOL_GPL(lowpan_header_compress);
789 790

MODULE_LICENSE("GPL");