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 465 466 467
		if (err)
			goto drop;
	}

	/* UDP data uncompression */
	if (iphc0 & LOWPAN_IPHC_NH_C) {
		struct udphdr uh;
		struct sk_buff *new;
		if (uncompress_udp_header(skb, &uh))
			goto drop;

468
		/* replace the compressed UDP head by the uncompressed UDP
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
		 * 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",
485
			       (u8 *)&uh, sizeof(uh));
486 487 488 489 490 491 492 493 494 495 496 497 498 499

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

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

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

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

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

	return rol8(val, shift);
}

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

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

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

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

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

	if (type != ETH_P_IPV6)
		return -EINVAL;

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

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

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

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

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

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

640
	/* hc format of TC is ECN | DSCP , original one is DSCP | ECN */
641 642 643 644 645 646 647 648 649 650 651 652 653
	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 */
654 655
			*hc_ptr = tmp;
			hc_ptr += 1;
656 657 658 659 660 661 662
		}
	} 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;
663 664 665
			*hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
			memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
			hc_ptr += 3;
666 667
		} else {
			/* compress nothing */
668
			memcpy(hc_ptr, hdr, 4);
669
			/* replace the top byte with new ECN | DSCP format */
670 671
			*hc_ptr = tmp;
			hc_ptr += 4;
672 673 674 675 676 677 678 679 680
		}
	}

	/* NOTE: payload length is always compressed */

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

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

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

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

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

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

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

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

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

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

MODULE_LICENSE("GPL");