Skip to content

Commit

Permalink
6lowpan: add udp compression via nhc layer
Browse files Browse the repository at this point in the history
This patch move UDP header compression and uncompression into the
generic 6LoWPAN nhc header compression layer. Moreover this patch
activates the nhc layer compression in iphc compression and
uncompression functions.

Signed-off-by: Alexander Aring <[email protected]>
Cc: Martin Townsend <[email protected]>
Reviewed-by: Stefan Schmidt <[email protected]>
Acked-by: Jukka Rissanen <[email protected]>
Signed-off-by: Marcel Holtmann <[email protected]>
  • Loading branch information
alexaring authored and holtmann committed Feb 14, 2015
1 parent 92aa7c6 commit cc6ed26
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 170 deletions.
19 changes: 18 additions & 1 deletion net/6lowpan/Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
config 6LOWPAN
menuconfig 6LOWPAN
tristate "6LoWPAN Support"
depends on IPV6
---help---
This enables IPv6 over Low power Wireless Personal Area Network -
"6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks.

menuconfig 6LOWPAN_NHC
tristate "Next Header Compression Support"
depends on 6LOWPAN
default y
---help---
Support for next header compression.

if 6LOWPAN_NHC

config 6LOWPAN_NHC_UDP
tristate "UDP Header Support"
default y
---help---
6LoWPAN IPv6 UDP Header compression according to RFC6282.

endif
5 changes: 4 additions & 1 deletion net/6lowpan/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
obj-$(CONFIG_6LOWPAN) := 6lowpan.o
obj-$(CONFIG_6LOWPAN) += 6lowpan.o

6lowpan-y := iphc.o nhc.o

#rfc6282 nhcs
obj-$(CONFIG_6LOWPAN_NHC_UDP) += nhc_udp.o
194 changes: 26 additions & 168 deletions net/6lowpan/iphc.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
#include <net/ipv6.h>
#include <net/af_ieee802154.h>

#include "nhc.h"

/* Uncompress address function for source and
* destination address(non-multicast).
*
Expand Down Expand Up @@ -224,77 +226,6 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
return 0;
}

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

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,
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,
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, sizeof(val));
uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
fail |= lowpan_fetch_skb(skb, &uh->dest,
sizeof(uh->dest));
break;
case LOWPAN_NHC_UDP_CS_P_11:
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 +
(val & 0x0f));
break;
default:
pr_debug("ERROR: unknown UDP format\n");
goto err;
}

pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
ntohs(uh->source), ntohs(uh->dest));

/* checksum */
if (tmp & LOWPAN_NHC_UDP_CS_C) {
pr_debug_ratelimited("checksum elided currently not supported\n");
goto err;
} else {
fail |= lowpan_fetch_skb(skb, &uh->check,
sizeof(uh->check));
}

/* UDP length needs to be infered from the lower layers
* here, we obtain the hint from the remaining size of the
* frame
*/
uh->len = htons(skb->len + sizeof(struct udphdr));
pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
} else {
pr_debug("ERROR: unsupported NH format\n");
goto err;
}

if (fail)
goto err;

return 0;
err:
return -EINVAL;
}

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

Expand Down Expand Up @@ -425,29 +356,11 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
return -EINVAL;
}

/* UDP data uncompression */
/* Next header data uncompression */
if (iphc0 & LOWPAN_IPHC_NH_C) {
struct udphdr uh;
const int needed = sizeof(struct udphdr) + sizeof(hdr);

if (uncompress_udp_header(skb, &uh))
return -EINVAL;

/* replace the compressed UDP head by the uncompressed UDP
* header
*/
err = skb_cow(skb, needed);
if (unlikely(err))
err = lowpan_nhc_do_uncompression(skb, dev, &hdr);
if (err < 0)
return err;

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",
(u8 *)&uh, sizeof(uh));

hdr.nexthdr = UIP_PROTO_UDP;
} else {
err = skb_cow(skb, sizeof(hdr));
if (unlikely(err))
Expand Down Expand Up @@ -500,79 +413,14 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
return rol8(val, shift);
}

static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
{
struct udphdr *uh;
u8 tmp;

/* In the case of RAW sockets the transport header is not set by
* the ip6 stack so we must set it ourselves
*/
if (skb->transport_header == skb->network_header)
skb_set_transport_header(skb, sizeof(struct ipv6hdr));

uh = udp_hdr(skb);

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)) {
pr_debug("UDP header: both ports compression to 4 bits\n");
/* compression value */
tmp = LOWPAN_NHC_UDP_CS_P_11;
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(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(hc_ptr, &tmp, sizeof(tmp));
/* source port */
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(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(hc_ptr, &tmp, sizeof(tmp));
/* source port */
tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
/* destination port */
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(hc_ptr, &tmp, sizeof(tmp));
/* source port */
lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
/* destination port */
lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
}

/* checksum is always inline */
lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));

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

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, *hc_ptr;
struct ipv6hdr *hdr;
u8 head[100] = {};
int addr_type;
int ret, addr_type;

if (type != ETH_P_IPV6)
return -EINVAL;
Expand Down Expand Up @@ -649,13 +497,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,

/* NOTE: payload length is always compressed */

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

if ((iphc0 & LOWPAN_IPHC_NH_C) == 0)
lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr,
sizeof(hdr->nexthdr));
/* 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;

/* Hop limit
* if 1: compress, encoding is 01
Expand Down Expand Up @@ -741,9 +588,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
}
}

/* UDP header compression */
if (hdr->nexthdr == UIP_PROTO_UDP)
compress_udp_header(&hc_ptr, skb);
/* next header compression */
if (iphc0 & LOWPAN_IPHC_NH_C) {
ret = lowpan_nhc_do_compression(skb, hdr, &hc_ptr);
if (ret < 0)
return ret;
}

head[0] = iphc0;
head[1] = iphc1;
Expand All @@ -761,4 +611,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
}
EXPORT_SYMBOL_GPL(lowpan_header_compress);

static int __init lowpan_module_init(void)
{
request_module_nowait("nhc_udp");

return 0;
}
module_init(lowpan_module_init);

MODULE_LICENSE("GPL");
Loading

0 comments on commit cc6ed26

Please sign in to comment.