The current udp compression/uncompression have several issues. A list of founded issues:
1. Byteordering issues in both functions which indicate that these functions never worked correctly. 2. Fixing derefecening issue which occurs a deferencing nullpointer sometimes. 3. Compress source port at first then destination port. This is switched in case ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) of udp header compress function. 4. Add failure case if we get a elided checksum while uncompress udp header. This is currently not supported. Other fixes/improvements are that this patch get udp compression working with the new fragmentation implementation and uses the lowpan_fetch_skb function. Signed-off-by: Alexander Aring <alex.ar...@gmail.com> Acked-by: Werner Almesberger <wer...@almesberger.net> --- net/ieee802154/6lowpan.c | 96 +++++++++++++++++++++++++++--------------------- net/ieee802154/6lowpan.h | 1 + 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index a819b28..2dbd675 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -341,29 +341,31 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) { struct udphdr *uh = udp_hdr(skb); - if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) == + if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) == LOWPAN_NHC_UDP_4BIT_PORT) && - ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) == + ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) == LOWPAN_NHC_UDP_4BIT_PORT)) { pr_debug("UDP header: both ports compression to 4 bits\n"); **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 + 1) = /* subtraction is faster */ + (u8)((ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT) + + ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4)); *hc06_ptr += 2; - } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) == + } 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"); **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 + 3) = (u8)(ntohs(uh->dest) - + LOWPAN_NHC_UDP_8BIT_PORT); *hc06_ptr += 4; - } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) == + } 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"); **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 + 1) = (u8)(ntohs(uh->source) - + LOWPAN_NHC_UDP_8BIT_PORT); + memcpy(*hc06_ptr + 2, &uh->dest, 2); *hc06_ptr += 4; } else { pr_debug("UDP header: can't compress\n"); @@ -405,67 +407,73 @@ static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) } static int -lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) +lowpan_uncompress_udp_header(struct sk_buff *skb, + struct udphdr *uh, size_t udplen) { - u8 tmp; + bool fail; + u8 tmp = 0, val = 0; - if (!uh) - goto err; - - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto err; + fail = lowpan_fetch_skb(skb, &tmp, 1); 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: - memcpy(&uh->source, &skb->data[0], 2); - memcpy(&uh->dest, &skb->data[2], 2); - skb_pull(skb, 4); + fail |= lowpan_fetch_skb(skb, &uh->source, 2); + fail |= lowpan_fetch_skb(skb, &uh->dest, 2); 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); + fail |= lowpan_fetch_skb(skb, &uh->source, 2); + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); 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); + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); + fail |= lowpan_fetch_skb(skb, &uh->dest, 2); 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); + fail |= lowpan_fetch_skb(skb, &val, 1); + 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; - break; } pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", - uh->source, uh->dest); + ntohs(uh->source), ntohs(uh->dest)); - /* copy checksum */ - memcpy(&uh->check, &skb->data[0], 2); - skb_pull(skb, 2); + /* checksum */ + if (tmp & LOWPAN_NHC_UDP_CS_C) { + pr_debug("checksum elided currently not supported"); + goto err; + } else { + fail |= lowpan_fetch_skb(skb, &uh->check, 2); + } /* * UDP lenght 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", uh->len); + if (udplen) + uh->len = htons(udplen); + else + 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; @@ -936,8 +944,14 @@ lowpan_process_data(struct sk_buff *skb, size_t d_size) if (iphc0 & LOWPAN_IPHC_NH_C) { struct udphdr uh; - if (lowpan_uncompress_udp_header(skb, &uh)) - goto drop; + if (d_size) { + if (lowpan_uncompress_udp_header(skb, &uh, d_size - + sizeof(struct ipv6hdr))) + goto drop; + } else { + if (lowpan_uncompress_udp_header(skb, &uh, 0)) + goto drop; + } skb_push(skb, sizeof(struct udphdr)); skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h index 05a2a37..0109b5d 100644 --- a/net/ieee802154/6lowpan.h +++ b/net/ieee802154/6lowpan.h @@ -231,6 +231,7 @@ #define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline, dest = 16 bit inline */ #define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */ +#define LOWPAN_NHC_UDP_CS_C 0x04 /* checksum elided */ static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data, const unsigned int len) -- 1.8.4 ------------------------------------------------------------------------------ October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60133471&iu=/4140/ostg.clktrk _______________________________________________ Linux-zigbee-devel mailing list Linux-zigbee-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel