summary refs log tree commit diff
path: root/net/6lowpan/iphc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/6lowpan/iphc.c')
-rw-r--r--net/6lowpan/iphc.c212
1 files changed, 105 insertions, 107 deletions
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index a1b7117a9600..142eef55c9e2 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -177,8 +177,8 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
 	struct sk_buff *new;
 	int stat;
 
-	new = skb_copy_expand(skb, sizeof(struct ipv6hdr),
-			      skb_tailroom(skb), GFP_ATOMIC);
+	new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
+			      GFP_ATOMIC);
 	kfree_skb(skb);
 
 	if (!new)
@@ -205,10 +205,9 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
 /* Uncompress function for multicast destination address,
  * when M bit is set.
  */
-static int
-lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
-				  struct in6_addr *ipaddr,
-				  const u8 dam)
+static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
+					     struct in6_addr *ipaddr,
+					     const u8 dam)
 {
 	bool fail;
 
@@ -254,41 +253,41 @@ lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
 	}
 
 	raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
-				ipaddr->s6_addr, 16);
+			ipaddr->s6_addr, 16);
 
 	return 0;
 }
 
-static int
-uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
+static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
 {
 	bool fail;
 	u8 tmp = 0, val = 0;
 
-	if (!uh)
-		goto err;
-
-	fail = lowpan_fetch_skb(skb, &tmp, 1);
+	fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
 
 	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:
-			fail |= lowpan_fetch_skb(skb, &uh->source, 2);
-			fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
+			fail |= lowpan_fetch_skb(skb, &uh->source,
+						 sizeof(uh->source));
+			fail |= lowpan_fetch_skb(skb, &uh->dest,
+						 sizeof(uh->dest));
 			break;
 		case LOWPAN_NHC_UDP_CS_P_01:
-			fail |= lowpan_fetch_skb(skb, &uh->source, 2);
-			fail |= lowpan_fetch_skb(skb, &val, 1);
+			fail |= lowpan_fetch_skb(skb, &uh->source,
+						 sizeof(uh->source));
+			fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
 			uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
 			break;
 		case LOWPAN_NHC_UDP_CS_P_10:
-			fail |= lowpan_fetch_skb(skb, &val, 1);
+			fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
 			uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
-			fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
+			fail |= lowpan_fetch_skb(skb, &uh->dest,
+						 sizeof(uh->dest));
 			break;
 		case LOWPAN_NHC_UDP_CS_P_11:
-			fail |= lowpan_fetch_skb(skb, &val, 1);
+			fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
 			uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
 					   (val >> 4));
 			uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
@@ -307,10 +306,11 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
 			pr_debug_ratelimited("checksum elided currently not supported\n");
 			goto err;
 		} else {
-			fail |= lowpan_fetch_skb(skb, &uh->check, 2);
+			fail |= lowpan_fetch_skb(skb, &uh->check,
+						 sizeof(uh->check));
 		}
 
-		/* UDP lenght needs to be infered from the lower layers
+		/* UDP length needs to be infered from the lower layers
 		 * here, we obtain the hint from the remaining size of the
 		 * frame
 		 */
@@ -333,9 +333,8 @@ err:
 static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
 
 int lowpan_process_data(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,
+			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)
 {
 	struct ipv6hdr hdr = {};
@@ -348,7 +347,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	/* another if the CID flag is set */
 	if (iphc1 & LOWPAN_IPHC_CID) {
 		pr_debug("CID flag is set, increase header with one\n");
-		if (lowpan_fetch_skb_u8(skb, &num_context))
+		if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
 			goto drop;
 	}
 
@@ -360,7 +359,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
 	 */
 	case 0: /* 00b */
-		if (lowpan_fetch_skb_u8(skb, &tmp))
+		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
 			goto drop;
 
 		memcpy(&hdr.flow_lbl, &skb->data[0], 3);
@@ -373,7 +372,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	 * ECN + DSCP (1 byte), Flow Label is elided
 	 */
 	case 2: /* 10b */
-		if (lowpan_fetch_skb_u8(skb, &tmp))
+		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
 			goto drop;
 
 		hdr.priority = ((tmp >> 2) & 0x0f);
@@ -383,7 +382,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
 	 */
 	case 1: /* 01b */
-		if (lowpan_fetch_skb_u8(skb, &tmp))
+		if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
 			goto drop;
 
 		hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
@@ -400,7 +399,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	/* Next Header */
 	if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
 		/* Next header is carried inline */
-		if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
+		if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
 			goto drop;
 
 		pr_debug("NH flag is set, next header carried inline: %02x\n",
@@ -411,7 +410,8 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
 		hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
 	} else {
-		if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
+		if (lowpan_fetch_skb(skb, &hdr.hop_limit,
+				     sizeof(hdr.hop_limit)))
 			goto drop;
 	}
 
@@ -421,8 +421,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 	if (iphc1 & LOWPAN_IPHC_SAC) {
 		/* Source address context based uncompression */
 		pr_debug("SAC bit is set. Handle context based source address.\n");
-		err = uncompress_context_based_src_addr(
-						skb, &hdr.saddr, tmp);
+		err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp);
 	} else {
 		/* Source address uncompression */
 		pr_debug("source address stateless compression\n");
@@ -443,8 +442,9 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 			pr_debug("dest: context-based mcast compression\n");
 			/* TODO: implement this */
 		} else {
-			err = lowpan_uncompress_multicast_daddr(
-						skb, &hdr.daddr, tmp);
+			err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
+								tmp);
+
 			if (err)
 				goto drop;
 		}
@@ -497,8 +497,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
 		hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
 		hdr.hop_limit, &hdr.daddr);
 
-	raw_dump_table(__func__, "raw header dump",
-		       (u8 *)&hdr, sizeof(hdr));
+	raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
 
 	return skb_deliver(skb, &hdr, dev, deliver_skb);
 
@@ -508,7 +507,7 @@ drop:
 }
 EXPORT_SYMBOL_GPL(lowpan_process_data);
 
-static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
+static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
 				  const struct in6_addr *ipaddr,
 				  const unsigned char *lladdr)
 {
@@ -519,24 +518,22 @@ static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
 		pr_debug("address compression 0 bits\n");
 	} else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
 		/* compress IID to 16 bits xxxx::XXXX */
-		memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
-		*hc06_ptr += 2;
+		lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
 		val = 2; /* 16-bits */
 		raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
-				*hc06_ptr - 2, 2);
+				*hc_ptr - 2, 2);
 	} else {
 		/* do not compress IID => xxxx::IID */
-		memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
-		*hc06_ptr += 8;
+		lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
 		val = 1; /* 64-bits */
 		raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
-				*hc06_ptr - 8, 8);
+				*hc_ptr - 8, 8);
 	}
 
 	return rol8(val, shift);
 }
 
-static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
+static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
 {
 	struct udphdr *uh = udp_hdr(skb);
 	u8 tmp;
@@ -548,46 +545,46 @@ static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
 		pr_debug("UDP header: both ports compression to 4 bits\n");
 		/* compression value */
 		tmp = LOWPAN_NHC_UDP_CS_P_11;
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 		/* source and destination port */
 		tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
 		      ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 	} else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
 			LOWPAN_NHC_UDP_8BIT_PORT) {
 		pr_debug("UDP header: remove 8 bits of dest\n");
 		/* compression value */
 		tmp = LOWPAN_NHC_UDP_CS_P_01;
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 		/* source port */
-		lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
+		lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
 		/* destination port */
 		tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 	} else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
 			LOWPAN_NHC_UDP_8BIT_PORT) {
 		pr_debug("UDP header: remove 8 bits of source\n");
 		/* compression value */
 		tmp = LOWPAN_NHC_UDP_CS_P_10;
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 		/* source port */
 		tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 		/* destination port */
-		lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
+		lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
 	} else {
 		pr_debug("UDP header: can't compress\n");
 		/* compression value */
 		tmp = LOWPAN_NHC_UDP_CS_P_00;
-		lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+		lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
 		/* source port */
-		lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
+		lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
 		/* destination port */
-		lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
+		lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
 	}
 
 	/* checksum is always inline */
-	lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check));
+	lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
 
 	/* skip the UDP header */
 	skb_pull(skb, sizeof(struct udphdr));
@@ -597,15 +594,16 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 			   unsigned short type, const void *_daddr,
 			   const void *_saddr, unsigned int len)
 {
-	u8 tmp, iphc0, iphc1, *hc06_ptr;
+	u8 tmp, iphc0, iphc1, *hc_ptr;
 	struct ipv6hdr *hdr;
 	u8 head[100] = {};
+	int addr_type;
 
 	if (type != ETH_P_IPV6)
 		return -EINVAL;
 
 	hdr = ipv6_hdr(skb);
-	hc06_ptr = head + 2;
+	hc_ptr = head + 2;
 
 	pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
 		 "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
@@ -630,8 +628,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 	raw_dump_inline(__func__, "daddr",
 			(unsigned char *)_daddr, IEEE802154_ADDR_LEN);
 
-	raw_dump_table(__func__,
-		       "sending raw skb network uncompressed packet",
+	raw_dump_table(__func__, "sending raw skb network uncompressed packet",
 		       skb->data, skb->len);
 
 	/* Traffic class, flow label
@@ -640,7 +637,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 	 * class depends on the presence of version and flow label
 	 */
 
-	/* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
+	/* hc format of TC is ECN | DSCP , original one is DSCP | ECN */
 	tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
 	tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
 
@@ -654,8 +651,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 			iphc0 |= LOWPAN_IPHC_TC_C;
 		} else {
 			/* compress only the flow label */
-			*hc06_ptr = tmp;
-			hc06_ptr += 1;
+			*hc_ptr = tmp;
+			hc_ptr += 1;
 		}
 	} else {
 		/* Flow label cannot be compressed */
@@ -663,15 +660,15 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 		    ((hdr->flow_lbl[0] & 0xF0) == 0)) {
 			/* compress only traffic class */
 			iphc0 |= LOWPAN_IPHC_TC_C;
-			*hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
-			memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
-			hc06_ptr += 3;
+			*hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
+			memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
+			hc_ptr += 3;
 		} else {
 			/* compress nothing */
-			memcpy(hc06_ptr, hdr, 4);
+			memcpy(hc_ptr, hdr, 4);
 			/* replace the top byte with new ECN | DSCP format */
-			*hc06_ptr = tmp;
-			hc06_ptr += 4;
+			*hc_ptr = tmp;
+			hc_ptr += 4;
 		}
 	}
 
@@ -681,10 +678,9 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 	if (hdr->nexthdr == UIP_PROTO_UDP)
 		iphc0 |= LOWPAN_IPHC_NH_C;
 
-	if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
-		*hc06_ptr = hdr->nexthdr;
-		hc06_ptr += 1;
-	}
+	if ((iphc0 & LOWPAN_IPHC_NH_C) == 0)
+		lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr,
+				    sizeof(hdr->nexthdr));
 
 	/* Hop limit
 	 * if 1:   compress, encoding is 01
@@ -703,84 +699,86 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
 		iphc0 |= LOWPAN_IPHC_TTL_255;
 		break;
 	default:
-		*hc06_ptr = hdr->hop_limit;
-		hc06_ptr += 1;
-		break;
+		lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit,
+				    sizeof(hdr->hop_limit));
 	}
 
+	addr_type = ipv6_addr_type(&hdr->saddr);
 	/* source address compression */
-	if (is_addr_unspecified(&hdr->saddr)) {
+	if (addr_type == IPV6_ADDR_ANY) {
 		pr_debug("source address is unspecified, setting SAC\n");
 		iphc1 |= LOWPAN_IPHC_SAC;
-	/* TODO: context lookup */
-	} else if (is_addr_link_local(&hdr->saddr)) {
-		iphc1 |= lowpan_compress_addr_64(&hc06_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");
-		memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
-		hc06_ptr += 16;
+		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);
+		}
 	}
 
+	addr_type = ipv6_addr_type(&hdr->daddr);
 	/* destination address compression */
-	if (is_addr_mcast(&hdr->daddr)) {
+	if (addr_type & IPV6_ADDR_MULTICAST) {
 		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 */
-			*hc06_ptr = hdr->daddr.s6_addr[15];
-			hc06_ptr += 1;
+			lowpan_push_hc_data(&hc_ptr,
+					    &hdr->daddr.s6_addr[15], 1);
 		} 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 */
-			*hc06_ptr = hdr->daddr.s6_addr[1];
-			memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
-			hc06_ptr += 4;
+			lowpan_push_hc_data(&hc_ptr,
+					    &hdr->daddr.s6_addr[1], 1);
+			lowpan_push_hc_data(&hc_ptr,
+					    &hdr->daddr.s6_addr[13], 3);
 		} 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 */
-			*hc06_ptr = hdr->daddr.s6_addr[1];
-			memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
-			hc06_ptr += 6;
+			lowpan_push_hc_data(&hc_ptr,
+					    &hdr->daddr.s6_addr[1], 1);
+			lowpan_push_hc_data(&hc_ptr,
+					    &hdr->daddr.s6_addr[11], 5);
 		} else {
 			pr_debug("using full address\n");
 			iphc1 |= LOWPAN_IPHC_DAM_00;
-			memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
-			hc06_ptr += 16;
+			lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
 		}
 	} else {
-		/* TODO: context lookup */
-		if (is_addr_link_local(&hdr->daddr)) {
-			iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+		if (addr_type & IPV6_ADDR_LINKLOCAL) {
+			/* TODO: context lookup */
+			iphc1 |= lowpan_compress_addr_64(&hc_ptr,
 				LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
 			pr_debug("dest address unicast link-local %pI6c "
-				"iphc1 0x%02x\n", &hdr->daddr, iphc1);
+				 "iphc1 0x%02x\n", &hdr->daddr, iphc1);
 		} else {
 			pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
-			memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
-			hc06_ptr += 16;
+			lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
 		}
 	}
 
 	/* UDP header compression */
 	if (hdr->nexthdr == UIP_PROTO_UDP)
-		compress_udp_header(&hc06_ptr, skb);
+		compress_udp_header(&hc_ptr, skb);
 
 	head[0] = iphc0;
 	head[1] = iphc1;
 
 	skb_pull(skb, sizeof(struct ipv6hdr));
 	skb_reset_transport_header(skb);
-	memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
+	memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head);
 	skb_reset_network_header(skb);
 
-	pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len);
+	pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len);
 
 	raw_dump_table(__func__, "raw skb data dump compressed",
 		       skb->data, skb->len);