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

Reply via email to