6loWPAN: Correct some fragmentation handling
This commit is contained in:
parent
3ea3fbcef1
commit
47647eac8f
@ -101,8 +101,7 @@
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* Input Parameters:
|
||||
* ieee - Pointer to IEEE802.15.4 MAC driver structure.
|
||||
* destip - Pointer to the IPv6 header to "compress"
|
||||
* ipv6hdr - Pointer to the IPv6 header to "compress"
|
||||
* fptr - Pointer to the beginning of the frame under construction
|
||||
*
|
||||
* Returned Value:
|
||||
@ -110,8 +109,7 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
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",
|
||||
|
@ -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).
|
||||
*/
|
||||
|
@ -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?
|
||||
*/
|
||||
|
@ -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).
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user