From 2dab490cee0d2c175c0eef354b1964d2e147ed64 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Fri, 13 Oct 2017 13:31:53 -0600
Subject: [PATCH] 6LoWPAN:  Fix a whole in the logic of the previous commit. 
 It turns out that g_uncomp_hdrlen has other usages so it cannot be modified
 as I was doing.  Instead, I needed to add a separate localt variable,
 protosize, to keep track of the two usages of g_uncomp_hdrlen.

---
 net/sixlowpan/sixlowpan_input.c | 103 ++++++++++++++++++++------------
 1 file changed, 66 insertions(+), 37 deletions(-)

diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c
index ed27d34a04..9890c8a547 100644
--- a/net/sixlowpan/sixlowpan_input.c
+++ b/net/sixlowpan/sixlowpan_input.c
@@ -151,10 +151,9 @@ static uint8_t g_bitbucket[UNCOMP_MAXHDR];
  ****************************************************************************/
 
 static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr,
-                                         FAR uint8_t *bptr, bool proto)
+                                         FAR uint8_t *bptr)
 {
   FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
-  uint16_t protosize;
 
   /* Put uncompressed IPv6 header in d_buf. */
 
@@ -165,54 +164,75 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr,
 
   g_frame_hdrlen  += IPv6_HDRLEN;
   g_uncomp_hdrlen += IPv6_HDRLEN;
+}
 
-  /* Does a protocol header follow the IPv6 header? */
+/****************************************************************************
+ * Name: sixlowpan_uncompress_ipv6proto
+ *
+ * Description:
+ *   Copy the protocol header following the IPv4 header
+ *
+ * Input Parameters:
+ *   fptr  - Pointer to the beginning of the frame under construction
+ *   bptr  - Output goes here.  Normally this is a known offset into d_buf,
+ *           may be redirected to g_bitbucket on the case of FRAGN frames.
+ *   proto - True: Copy the protocol header following the IPv6 header too.
+ *
+ * Returned Value:
+ *   The size of the protocol header that was copied.
+ *
+ ****************************************************************************/
 
-  if (proto)
-    {
-      /* Yes.. Copy the following protocol header. */
+static uint16_t sixlowpan_uncompress_ipv6proto(FAR uint8_t *fptr,
+                                               FAR uint8_t *bptr)
+{
+  FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
+  uint16_t protosize = 0;
 
-      switch (ipv6->proto)
-        {
+  /* Copy the following protocol header. */
+
+  switch (ipv6->proto)
+    {
 #ifdef CONFIG_NET_TCP
-        case IP_PROTO_TCP:
-          {
-            FAR struct tcp_hdr_s *tcp =
-              (FAR struct tcp_hdr_s *)(fptr + g_frame_hdrlen);
+    case IP_PROTO_TCP:
+      {
+        FAR struct tcp_hdr_s *tcp =
+          (FAR struct tcp_hdr_s *)(fptr + g_frame_hdrlen);
 
-            /* The TCP header length is encoded in the top 4 bits of the
-             * tcpoffset field (in units of 32-bit words).
-             */
+        /* The TCP header length is encoded in the top 4 bits of the
+         * tcpoffset field (in units of 32-bit words).
+         */
 
-            protosize = ((uint16_t)tcp->tcpoffset >> 4) << 2;
-          }
-          break;
+        protosize = ((uint16_t)tcp->tcpoffset >> 4) << 2;
+      }
+      break;
 #endif
 
 #ifdef CONFIG_NET_UDP
-        case IP_PROTO_UDP:
-          protosize = sizeof(struct udp_hdr_s);
-          break;
+    case IP_PROTO_UDP:
+      protosize = sizeof(struct udp_hdr_s);
+      break;
 #endif
 
 #ifdef CONFIG_NET_ICMPv6
-        case IP_PROTO_ICMP6:
-          protosize = sizeof(struct icmpv6_hdr_s);
-          break;
+    case IP_PROTO_ICMP6:
+      protosize = sizeof(struct icmpv6_hdr_s);
+      break;
 #endif
 
-        default:
-          nwarn("WARNING: Unrecognized proto: %u\n", ipv6->proto);
-          return;
-        }
+    default:
+      nwarn("WARNING: Unrecognized proto: %u\n", ipv6->proto);
+      return 0;
+    }
 
-      /* Copy the protocol header. */
+  /* Copy the protocol header. */
 
-      memcpy((FAR uint8_t *)ipv6 + g_uncomp_hdrlen, fptr + g_frame_hdrlen,
-             protosize);
+  memcpy((FAR uint8_t *)ipv6 + g_uncomp_hdrlen, fptr + g_frame_hdrlen,
+         protosize);
 
-      g_frame_hdrlen += protosize;
-    }
+  g_frame_hdrlen   += protosize;
+  g_uncomp_hdrlen  += protosize;
+  return protosize;
 }
 
 /****************************************************************************
@@ -266,6 +286,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
   uint16_t paysize;           /* Size of the data payload */
   uint16_t fragtag   = 0;     /* Tag of the fragment */
   uint8_t fragoffset = 0;     /* Offset of the fragment in the IP packet */
+  uint8_t protosize  = 0;     /* Length of the protocal header (treated like payload) */
   bool isfrag        = false; /* true: Frame is a fragment */
   bool isfrag1       = false; /* true: Frame is the first fragement of the series */
   int reqsize;                /* Required buffer size */
@@ -447,11 +468,19 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
     {
       ninfo("IPv6 Dispatch\n");
 
-      /* NOTE: A protocol header will follow only on a non-fragmented
-       * packet or on the first fragment of a fragmented packet.
+      /* Uncompress the IPv6 header */
+
+      sixlowpan_uncompress_ipv6hdr(fptr, bptr);
+
+      /* A protocol header will follow the IPv6 header only on a non-
+       * fragmented packet or on the first fragment of a fragmented
+       * packet.
        */
 
-      sixlowpan_uncompress_ipv6hdr(fptr, bptr, !isfrag || isfrag1);
+      if (!isfrag || isfrag1)
+        {
+          protosize = sixlowpan_uncompress_ipv6proto(fptr, bptr);
+        }
     }
   else
     {
@@ -470,7 +499,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
        * begin placing the data payload.
        */
 
-      reass->rb_boffset = g_uncomp_hdrlen;
+      reass->rb_boffset = g_uncomp_hdrlen - protosize;
     }
 
   /* No.. is this a subsequent fragment in the same sequence? */
-- 
GitLab