This patch adds support for compression/decompression of UDP header of ipv6 datagram.
Derived from Contiki OS Signed-off-by: Alexander Smirnov <alex.bluesman.smir...@gmail.com> --- net/ieee802154/6lowpan.c | 101 +++++++++++++++++++++++++++++++++++++++++++-- net/ieee802154/6lowpan.h | 5 ++ 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 1ee6d1c..9f3e270 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -367,8 +367,6 @@ static int lowpan_header_create(struct sk_buff *skb, if (hdr->nexthdr == UIP_PROTO_UDP) iphc0 |= LOWPAN_IPHC_NH_C; -/* TODO: next header compression */ - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { *hc06_ptr = hdr->nexthdr; hc06_ptr += 1; @@ -456,8 +454,53 @@ static int lowpan_header_create(struct sk_buff *skb, } } - /* TODO: UDP header compression */ - /* TODO: Next Header compression */ + /* UDP header compression */ + if (hdr->nexthdr == UIP_PROTO_UDP) { + struct udphdr *uh = udp_hdr(skb); + + pr_debug("(%s): UDP header compression\n", __func__); + + if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT) && + ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT)) { + pr_debug("(%s): both ports compression to 4 bits\n", + __func__); + *hc06_ptr = LOWPAN_NHC_UDP_CS_P_11; + *(hc06_ptr + 1) = /* subtraction is faster */ + (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) + + ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4)); + hc06_ptr += 2; + } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("(%s): remove 8 bits of dest\n", __func__); + *hc06_ptr = LOWPAN_NHC_UDP_CS_P_01; + memcpy(hc06_ptr + 1, &uh->source, 2); + *(hc06_ptr + 3) = + (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT); + hc06_ptr += 4; + } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("(%s): remove 8 bits of source\n", __func__); + *hc06_ptr = LOWPAN_NHC_UDP_CS_P_10; + memcpy(hc06_ptr + 1, &uh->dest, 2); + *(hc06_ptr + 3) = + (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT); + hc06_ptr += 4; + } else { + pr_debug("(%s): can't compress header\n", __func__); + *hc06_ptr = LOWPAN_NHC_UDP_CS_P_00; + memcpy(hc06_ptr + 1, &uh->source, 2); + memcpy(hc06_ptr + 3, &uh->dest, 2); + hc06_ptr += 5; + } + + /* checksum is always inline */ + memcpy(hc06_ptr, &uh->check, 2); + hc06_ptr += 2; + } + + /* TODO: other NH types support? */ head[0] = iphc0; head[1] = iphc1; @@ -799,7 +842,55 @@ lowpan_process_data(struct sk_buff *skb) goto drop; } - /* TODO: UDP header parse */ + /* UDP data uncompression */ + if (iphc0 & LOWPAN_IPHC_NH_C) { + tmp = lowpan_fetch_skb_u8(skb); + + if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { + struct udphdr *uh = udp_hdr(skb); + + pr_debug("(%s): UDP header uncompression\n", __func__); + switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { + case LOWPAN_NHC_UDP_CS_P_00: + memcpy(&uh->source, &skb->data[0], 2); + memcpy(&uh->dest, &skb->data[2], 2); + skb_pull(skb, 4); + break; + case LOWPAN_NHC_UDP_CS_P_01: + memcpy(&uh->source, &skb->data[0], 2); + uh->dest = + skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT; + skb_pull(skb, 3); + break; + case LOWPAN_NHC_UDP_CS_P_10: + uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT; + memcpy(&uh->dest, &skb->data[1], 2); + skb_pull(skb, 3); + break; + case LOWPAN_NHC_UDP_CS_P_11: + uh->source = + LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4); + uh->dest = + LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f); + skb_pull(skb, 1); + break; + default: + pr_debug("(%s) ERROR: unknown UDP format\n", __func__); + goto drop; + } + + pr_debug("(%s): uncompressed UDP ports: src = %d, dst = %d\n", + __func__, uh->source, uh->dest); + + /* copy checksum */ + memcpy(&uh->check, &skb->data[0], 2); + skb_pull(skb, 2); + } else { + pr_debug("(%s): ERROR: unsupported NH format\n", + __func__); + goto drop; + } + } /* Not fragmented package */ hdr.payload_len = htons(skb->len); diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h index eeb5446..31e0d5e 100644 --- a/net/ieee802154/6lowpan.h +++ b/net/ieee802154/6lowpan.h @@ -219,6 +219,11 @@ #define LOWPAN_NHC_UDP_CHECKSUMC 0x04 #define LOWPAN_NHC_UDP_CHECKSUMI 0x00 +#define LOWPAN_NHC_UDP_4BIT_PORT 0xF0B0 +#define LOWPAN_NHC_UDP_4BIT_MASK 0xFFF0 +#define LOWPAN_NHC_UDP_8BIT_PORT 0xF000 +#define LOWPAN_NHC_UDP_8BIT_MASK 0xFF00 + /* values for port compression, _with checksum_ ie bit 5 set to 0 */ #define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */ #define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline, -- 1.7.2.3 ------------------------------------------------------------------------------ The demand for IT networking professionals continues to grow, and the demand for specialized networking skills is growing even more rapidly. Take a complimentary Learning@Cisco Self-Assessment and learn about Cisco certifications, training, and career opportunities. http://p.sf.net/sfu/cisco-dev2dev _______________________________________________ Linux-zigbee-devel mailing list Linux-zigbee-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel