6loWPAN: Correct some fragmentation handling

This commit is contained in:
Gregory Nutt 2017-04-07 09:49:10 -06:00
parent 3ea3fbcef1
commit 47647eac8f
4 changed files with 139 additions and 65 deletions

View File

@ -101,17 +101,15 @@
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Input Parameters:
* ieee - Pointer to IEEE802.15.4 MAC driver structure.
* destip - Pointer to the IPv6 header to "compress"
* fptr - Pointer to the beginning of the frame under construction
* ipv6hdr - Pointer to the IPv6 header to "compress"
* fptr - Pointer to the beginning of the frame under construction
*
* Returned Value:
* None
*
****************************************************************************/
static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
FAR const struct ipv6_hdr_s *destip,
static void sixlowpan_compress_ipv6hdr(FAR const struct ipv6_hdr_s *ipv6hdr,
FAR uint8_t *fptr)
{
/* Indicate the IPv6 dispatch and length */
@ -121,11 +119,93 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
/* Copy the IPv6 header and adjust pointers */
memcpy(&fptr[g_frame_hdrlen] , destip, IPv6_HDRLEN);
memcpy(&fptr[g_frame_hdrlen] , ipv6hdr, IPv6_HDRLEN);
g_frame_hdrlen += IPv6_HDRLEN;
g_uncomp_hdrlen += IPv6_HDRLEN;
}
/****************************************************************************
* Name: sixlowpan_copy_protohdr
*
* Description:
* The IPv6 header should have already been processed (as reflected in the
* g_uncomphdrlen). But we probably still need to copy the following
* protocol header.
*
* Input Parameters:
* ipv6hdr - Pointer to the IPv6 header to "compress"
* fptr - Pointer to the beginning of the frame under construction
*
* Returned Value:
* None. But g_frame_hdrlen and g_uncomp_hdrlen updated.
*
****************************************************************************/
static void sixlowpan_copy_protohdr(FAR const struct ipv6_hdr_s *ipv6hdr,
FAR uint8_t *fptr)
{
uint16_t combined;
uint16_t protosize;
uint16_t copysize;
/* What is the total size of the IPv6 + protocol header? */
switch (ipv6hdr->proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
combined = sizeof(struct ipv6tcp_hdr_s);
protosize = sizeof(struct tcp_hdr_s);
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
combined = sizeof(struct ipv6udp_hdr_s);
protosize = sizeof(struct udp_hdr_s);
break;
#endif
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6:
combined = sizeof(struct ipv6icmp_hdr_s);
protosize = sizeof(struct icmpv6_hdr_s);
break;
#endif
default:
nwarn("WARNING: Unrecognized proto: %u\n", ipv6hdr->proto);
combined = sizeof(struct ipv6_hdr_s);
protosize = 0;
break;
}
/* Copy the remaining protocol header. */
if (g_uncomp_hdrlen > IPv6_HDRLEN)
{
nwarn("WARNING: Protocol header not copied: "
"g_uncomp_hdren=%u IPv6_HDRLEN=%u\n",
g_uncomp_hdrlen, IPv6_HDRLEN);
return;
}
copysize = combined - g_uncomp_hdrlen;
if (copysize != protosize)
{
nwarn("WARNING: Protocol header size mismatch: "
"g_uncomp_hdren=%u copysize=%u protosize=%u\n",
g_uncomp_hdrlen, copysize, protosize);
return;
}
memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)ipv6hdr + g_uncomp_hdrlen,
copysize);
g_frame_hdrlen += copysize;
g_uncomp_hdrlen += copysize;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -172,6 +252,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
FAR uint8_t *fptr;
int framer_hdrlen;
struct rimeaddr_s bcastmac;
uint16_t paysize;
#ifdef CONFIG_NET_6LOWPAN_FRAG
uint16_t outlen = 0;
#endif
@ -267,7 +348,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
{
/* Small.. use IPv6 dispatch (no compression) */
sixlowpan_compress_ipv6hdr(ieee, destip, fptr);
sixlowpan_compress_ipv6hdr(destip, fptr);
}
ninfo("Header of length %d\n", g_frame_hdrlen);
@ -276,9 +357,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
/* Check if we need to fragment the packet into several frames */
if ((int)buflen - (int)g_uncomp_hdrlen >
(int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen -
(int)g_frame_hdrlen)
if (buflen > (CONFIG_NET_6LOWPAN_MAXPAYLOAD - g_frame_hdrlen))
{
#ifdef CONFIG_NET_6LOWPAN_FRAG
/* ieee->i_framelist will hold the generated frames; frames will be
@ -295,7 +374,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
* The following fragments contain only the fragn dispatch.
*/
ninfo("Fragmentation sending packet length %d\n", buflen);
ninfo("Sending fragmented packet length %d\n", buflen);
/* Create 1st Fragment */
/* Add the frame header using the pre-allocated IOB. */
@ -325,25 +404,28 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
PUTINT16(fptr, RIME_FRAG_DISPATCH_SIZE,
((SIXLOWPAN_DISPATCH_FRAG1 << 8) | buflen));
PUTINT16(fptr, RIME_FRAG_TAG, ieee->i_dgramtag);
ieee->i_dgramtag++;
g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
/* Copy protocol header that follows the IPv6 header */
sixlowpan_copy_protohdr(destip, fptr);
/* Copy payload and enqueue */
g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
g_rime_payloadlen =
(CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_frame_hdrlen) & 0xf8;
memcpy(fptr + g_frame_hdrlen,
(FAR uint8_t *)destip + g_uncomp_hdrlen, g_rime_payloadlen);
iob->io_len += g_rime_payloadlen + g_frame_hdrlen;
paysize = (CONFIG_NET_6LOWPAN_MAXPAYLOAD - g_frame_hdrlen) & 0xf8;
memcpy(fptr + g_frame_hdrlen, buf, paysize);
/* Set outlen to what we already sent from the IP payload */
outlen = g_rime_payloadlen + g_uncomp_hdrlen;
iob->io_len = paysize + g_frame_hdrlen;
outlen = paysize;
ninfo("First fragment: length %d, tag %d\n",
g_rime_payloadlen, ieee->i_dgramtag);
paysize, ieee->i_dgramtag);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data, iob->io_len);
@ -394,30 +476,33 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
PUTINT16(fptr, RIME_FRAG_TAG, ieee->i_dgramtag);
fptr[RIME_FRAG_OFFSET] = outlen >> 3;
/* Copy protocol header that follows the IPv6 header */
sixlowpan_copy_protohdr(destip, fptr);
/* Copy payload and enqueue */
/* Check for the last fragment */
if (buflen - outlen < g_rime_payloadlen)
if (buflen - outlen < paysize)
{
/* Last fragment */
/* Last fragment, truncate to the correct length */
g_rime_payloadlen = buflen - outlen;
paysize = buflen - outlen;
}
else
{
g_rime_payloadlen =
(CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_frame_hdrlen) & 0xf8;
paysize = (CONFIG_NET_6LOWPAN_MAXPAYLOAD - g_frame_hdrlen) & 0xf8;
}
memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)destip + outlen,
g_rime_payloadlen);
iob->io_len = g_rime_payloadlen + g_frame_hdrlen;
memcpy(fptr + g_frame_hdrlen, buf + outlen, paysize);
/* Set outlen to what we already sent from the IP payload */
outlen += (g_rime_payloadlen + g_uncomp_hdrlen);
iob->io_len = paysize + g_frame_hdrlen;
outlen += paysize;
ninfo("sixlowpan output: fragment offset %d, length %d, tag %d\n",
outlen >> 3, g_rime_payloadlen, ieee->i_dgramtag);
ninfo("Fragment offset %d, length %d, tag %d\n",
outlen >> 3, paysize, ieee->i_dgramtag);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data,
iob->io_len);
@ -453,11 +538,14 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee,
DEBUGASSERT(verify == framer_hdrlen);
UNUSED(verify);
/* Copy protocol header that follows the IPv6 header */
sixlowpan_copy_protohdr(destip, fptr);
/* Copy the payload and queue */
memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)destip + g_uncomp_hdrlen,
buflen - g_uncomp_hdrlen);
iob->io_len = buflen - g_uncomp_hdrlen + g_frame_hdrlen;
memcpy(fptr + g_frame_hdrlen, buf, buflen);
iob->io_len = buflen + g_frame_hdrlen;
ninfo("Non-fragmented: length %d\n", iob->io_len);
sixlowpan_dumpbuffer("Outgoing frame",

View File

@ -54,15 +54,6 @@
* during that processing
*/
/* The length of the payload in the Rime buffer.
*
* The payload is what comes after the compressed or uncompressed headers
* (can be the IP payload if the IP header only is compressed or the UDP
* payload if the UDP header is also compressed)
*/
uint8_t g_rime_payloadlen;
/* g_uncomp_hdrlen is the length of the headers before compression (if HC2
* is used this includes the UDP header in addition to the IP header).
*/

View File

@ -213,6 +213,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
FAR uint8_t *hc1; /* Convenience pointer to HC1 data */
uint16_t fragsize = 0; /* Size of the IP packet (read from fragment) */
uint16_t paysize; /* Size of the data payload */
uint8_t fragoffset = 0; /* Offset of the fragment in the IP packet */
int reqsize; /* Required buffer size */
int hdrsize; /* Size of the IEEE802.15.4 header */
@ -282,12 +283,12 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee,
fragtag = GETINT16(payptr, RIME_FRAG_TAG);
fragsize = GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff;
ninfo("FRAGN: size %d, tag %d, offset %d\n",
ninfo("FRAGN: size=%d tag=%d offset=%d\n",
fragsize, fragtag, fragoffset);
g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN;
ninfo("FRAGN: i_accumlen %d g_rime_payloadlen %d fragsize %d\n",
ninfo("FRAGN: i_accumlen=%d paysize=%u fragsize=%u\n",
ieee->i_accumlen, iob->io_len - g_frame_hdrlen, fragsize);
/* Indicate that this frame is a another fragment for reassembly */
@ -501,28 +502,28 @@ copypayload:
* and g_frame_hdrlen are non-zerio, fragoffset is.
*/
g_rime_payloadlen = iob->io_len - g_frame_hdrlen;
if (g_rime_payloadlen > CONFIG_NET_6LOWPAN_MTU)
paysize = iob->io_len - g_frame_hdrlen;
if (paysize > CONFIG_NET_6LOWPAN_MTU)
{
nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n",
g_rime_payloadlen, CONFIG_NET_6LOWPAN_MTU);
paysize, CONFIG_NET_6LOWPAN_MTU);
return OK;
}
/* Sanity-check size of incoming packet to avoid buffer overflow */
reqsize = g_uncomp_hdrlen + (uint16_t) (fragoffset << 3) + g_rime_payloadlen;
reqsize = g_uncomp_hdrlen + (uint16_t) (fragoffset << 3) + paysize;
if (reqsize > CONFIG_NET_6LOWPAN_MTU)
{
ninfo("Required buffer size: %d+%d+%d=%d Available: %d\n",
g_uncomp_hdrlen, (int)(fragoffset << 3), g_rime_payloadlen,
g_uncomp_hdrlen, (int)(fragoffset << 3), paysize,
reqsize, CONFIG_NET_6LOWPAN_MTU);
return -ENOMEM;
}
memcpy((FAR uint8_t *)ieee->i_dev.d_buf + g_uncomp_hdrlen +
(int)(fragoffset << 3), payptr + g_frame_hdrlen,
g_rime_payloadlen);
paysize);
#ifdef CONFIG_NET_6LOWPAN_FRAG
/* Update ieee->i_accumlen if the frame is a fragment, ieee->i_pktlen
@ -548,15 +549,14 @@ copypayload:
}
else
{
ieee->i_accumlen += g_rime_payloadlen;
ieee->i_accumlen += paysize;
}
ninfo("i_accumlen %d, g_rime_payloadlen %d\n",
ieee->i_accumlen, g_rime_payloadlen);
ninfo("i_accumlen %d, paysize %d\n", ieee->i_accumlen, paysize);
}
else
{
ieee->i_pktlen = g_rime_payloadlen + g_uncomp_hdrlen;
ieee->i_pktlen = paysize + g_uncomp_hdrlen;
}
/* If we have a full IP packet in sixlowpan_buf, deliver it to
@ -580,7 +580,7 @@ copypayload:
#else
/* Deliver the packet to the IP stack */
ieee->i_dev.d_len = g_rime_payloadlen + g_uncomp_hdrlen;
ieee->i_dev.d_len = paysize + g_uncomp_hdrlen;
return INPUT_COMPLETE;
#endif /* CONFIG_NET_6LOWPAN_FRAG */
}
@ -706,6 +706,10 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee)
ret = sixlowpan_frame_process(ieee, iob);
/* Free the IOB the held the consumed frame */
iob_free(iob);
/* Was the frame successfully processed? Is the packet in d_buf fully
* reassembled?
*/

View File

@ -409,15 +409,6 @@ struct frame802154_s
extern FAR uint8_t *g_rimeptr;
/* The length of the payload in the Rime buffer.
*
* The payload is what comes after the compressed or uncompressed headers
* (can be the IP payload if the IP header only is compressed or the UDP
* payload if the UDP header is also compressed)
*/
extern uint8_t g_rime_payloadlen;
/* g_uncomp_hdrlen is the length of the headers before compression (if HC2
* is used this includes the UDP header in addition to the IP header).
*/