From 53c0938b532631458879a97c0fa273abb9920fa3 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 13 Oct 2017 11:07:43 -0600 Subject: [PATCH] 6LoWPAN: Correct a bug in handling uncompressed frames (IPv6 dispatch) --- net/sixlowpan/sixlowpan_input.c | 83 +++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index 66d53e1e12..ed27d34a04 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -140,16 +140,18 @@ static uint8_t g_bitbucket[UNCOMP_MAXHDR]; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * 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. + * 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: * None * ****************************************************************************/ -static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr) +static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, + FAR uint8_t *bptr, bool proto) { FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr; uint16_t protosize; @@ -164,49 +166,53 @@ static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr, FAR uint8_t *bptr) g_frame_hdrlen += IPv6_HDRLEN; g_uncomp_hdrlen += IPv6_HDRLEN; - /* Copy the following protocol header, */ + /* Does a protocol header follow the IPv6 header? */ - switch (ipv6->proto) - { + if (proto) + { + /* Yes.. 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; + } - /* 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_uncomp_hdrlen += protosize; + g_frame_hdrlen += protosize; + } } /**************************************************************************** @@ -261,7 +267,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, uint16_t fragtag = 0; /* Tag of the fragment */ uint8_t fragoffset = 0; /* Offset of the fragment in the IP packet */ bool isfrag = false; /* true: Frame is a fragment */ - bool isfirstfrag = false; /* true: Frame is the first fragement of the series */ + bool isfrag1 = false; /* true: Frame is the first fragement of the series */ int reqsize; /* Required buffer size */ int hdrsize; /* Size of the IEEE802.15.4 header */ int ret; @@ -344,7 +350,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, /* Indicate the first fragment of the reassembly */ bptr = reass->rb_buf; - isfirstfrag = true; + isfrag1 = true; isfrag = true; } break; @@ -440,7 +446,12 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, if (hc1[SIXLOWPAN_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_IPV6) { ninfo("IPv6 Dispatch\n"); - sixlowpan_uncompress_ipv6hdr(fptr, bptr); + + /* NOTE: A protocol header will follow only on a non-fragmented + * packet or on the first fragment of a fragmented packet. + */ + + sixlowpan_uncompress_ipv6hdr(fptr, bptr, !isfrag || isfrag1); } else { @@ -453,7 +464,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio, /* Is this the first fragment is a sequence? */ - if (isfirstfrag) + if (isfrag1) { /* Yes.. Remember the offset from the beginning of d_buf where we * begin placing the data payload.