6LoWPAN: The original, Contiki-based design used only a single buffer for reassemblying larger packets. This could be a problem issue for hub configurations which really need the capability concurrently reassemble multiple incoming streams concurrently. These was also a design issue in that the reassembly buffer could be corrupted by outgoing packets. The design was extended to support multiple reassembly buffers, each associated with the reassembly tag and source address. This assures that there can be be no corruption of the reassembly once it has started.

This commit is contained in:
Gregory Nutt
2017-08-26 10:00:47 -06:00
parent f96a7cbc59
commit 88a87f8e3f
25 changed files with 1039 additions and 366 deletions
+34
View File
@@ -12,6 +12,40 @@ config NET_6LOWPAN_FRAG
CONFIG_NET_6LOWPAN_FRAG specifies if 6lowpan fragmentation should be
used or not. Fragmentation is on by default.
config NET_6LOWPAN_NREASSBUF
int "Number of preallocated reassembly buffers"
default 2
depends on NET_6LOWPAN_FRAG
---help---
Large IPv6 packets will be fragmented by 6LoWPAN into multiple
frames and reconstitued into a reassembly buffer on the receiving
side. Each concurrent reassembly requires one buffer. Reassembly
buffers are large: The size of the 6LoWPAN MTU plus some overhead
for the reassembly state.
Some reassembly buffers may be preallocated; some may be allocated
dynamically from the stack. The former require more static memory
usage; the later require additional CPU cycles to perform the
allocation and may effect deterministic behavior. So this is a
trade-off between resources and performance. If the number of pre-
allocated reassembly buffers are exhausted, the reassembly will
continue with dynamically allocated reassembly buffers.
This behavior can be changed with CONFIG_NET_6LOWPAN_REASS_STATIC
config NET_6LOWPAN_REASS_STATIC
bool "Static reassembly buffers"
default n
depends on NET_6LOWPAN_FRAG
---help---
By default, reassembly buffers may be allocated dynamically from the
stack when all of the statically allocation reassembly buffers are
in use. This will equire additional CPU cycles to perform the
allocation and may effect deterministic behavior. This option may
be selected to suppress all dynamica allocation of reassembly
buffers. In that case, only static reassembly buffers are available;
when those are exhausted, frames that require reassembly will be lost.
config NET_6LOWPAN_FRAMELEN
int "Max Radio Frame Size"
default 127
+4
View File
@@ -68,6 +68,10 @@ ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC06),y)
NET_CSRCS += sixlowpan_hc06.c
endif
ifeq ($(CONFIG_NET_6LOWPAN_FRAG),y)
NET_CSRCS += sixlowpan_reassbuf.c
endif
# Include the sixlowpan directory in the build
DEPPATH += --dep-path sixlowpan
+14 -7
View File
@@ -54,6 +54,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
@@ -384,9 +385,9 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
FAR uint8_t *fptr;
int framer_hdrlen;
struct netdev_varaddr_s bcastmac;
#ifdef CONFIG_NET_6LOWPAN_FRAG
uint16_t pktlen;
uint16_t paysize;
#ifdef CONFIG_NET_6LOWPAN_FRAG
uint16_t outlen = 0;
#endif
uint8_t protosize;
@@ -505,12 +506,18 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
* added at qtail.
*/
FAR struct sixlowpan_reassbuf_s *reass;
FAR struct iob_s *qhead;
FAR struct iob_s *qtail;
FAR uint8_t *frame1;
FAR uint8_t *fragptr;
uint16_t frag1_hdrlen;
/* Recover the reassembly buffer from the driver d_buf. */
reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
DEBUGASSERT(reass != NULL);
/* The outbound IPv6 packet is too large to fit into a single 15.4
* packet, so we fragment it into multiple packets and send them.
* The first fragment contains frag1 dispatch, then
@@ -548,7 +555,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
pktlen = buflen + g_uncomp_hdrlen + protosize;
PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE,
((SIXLOWPAN_DISPATCH_FRAG1 << 8) | pktlen));
PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, radio->r_dgramtag);
PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, reass->rb_dgramtag);
g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
@@ -575,7 +582,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
outlen = paysize;
ninfo("First fragment: length %d, tag %d\n",
paysize, radio->r_dgramtag);
paysize, reass->rb_dgramtag);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data, iob->io_len);
@@ -630,7 +637,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE,
((SIXLOWPAN_DISPATCH_FRAGN << 8) | pktlen));
PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, radio->r_dgramtag);
PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, reass->rb_dgramtag);
fragptr[SIXLOWPAN_FRAG_OFFSET] = outlen >> 3;
fragn_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN;
@@ -654,8 +661,8 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
iob->io_len = paysize + fragn_hdrlen;
outlen += paysize;
ninfo("Fragment offset=%d, paysize=%d, r_dgramtag=%d\n",
outlen >> 3, paysize, radio->r_dgramtag);
ninfo("Fragment offset=%d, paysize=%d, rb_dgramtag=%d\n",
outlen >> 3, paysize, reass->rb_dgramtag);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data,
iob->io_len);
@@ -697,7 +704,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
/* Update the datagram TAG value */
radio->r_dgramtag++;
reass->rb_dgramtag++;
#else
nerr("ERROR: Packet too large: %d\n", buflen);
nerr(" Cannot to be sent without fragmentation support\n");
+1
View File
@@ -61,6 +61,7 @@
#include <string.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include <nuttx/net/ip.h>
+1
View File
@@ -53,6 +53,7 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include "sixlowpan/sixlowpan_internal.h"
+6
View File
@@ -69,6 +69,12 @@
void sixlowpan_initialize(void)
{
#ifdef CONFIG_NET_6LOWPAN_FRAG
/* Initialize the reassembly buffer allocator */
sixlowpan_reass_initialize();
#endif
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
/* Initialize HC06 data data structures */
+138 -204
View File
@@ -54,10 +54,7 @@
#include <errno.h>
#include <debug.h>
#ifdef CONFIG_NET_6LOWPAN_FRAG
# include "nuttx/clock.h"
#endif
#include "nuttx/mm/iob.h"
#include "nuttx/net/netdev.h"
#include "nuttx/net/radiodev.h"
#include "nuttx/net/ip.h"
@@ -82,10 +79,6 @@
#define INPUT_PARTIAL 0 /* Frame processed successful, packet incomplete */
#define INPUT_COMPLETE 1 /* Frame processed successful, packet complete */
/* Re-assembly timeout in clock ticks */
#define NET_6LOWPAN_TIMEOUT SEC2TICK(CONFIG_NET_6LOWPAN_MAXAGE)
/* This is the size of a buffer large enough to hold the largest uncompressed
* HC06 or HC1 headers.
*/
@@ -132,50 +125,6 @@ static uint8_t g_bitbucket[UNCOMP_MAXHDR];
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_compare_fragsrc
*
* Description:
* Check if the fragment that we just received is from the same source as
* the previosly received fragements.
*
* Input Parameters:
* radio - Radio network device driver state instance
* metadata - Characteristics of the newly received frame
*
* Returned Value:
* true if the sources are the same.
*
****************************************************************************/
static bool sixlowpan_compare_fragsrc(FAR struct radio_driver_s *radio,
FAR const void *metadata)
{
struct netdev_varaddr_s fragsrc;
int ret;
/* Extract the source address from the 'metadata' */
ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc);
if (ret < 0)
{
nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
return false;
}
/* The addresses cannot match if they are not the same size */
if (fragsrc.nv_addrlen == radio->r_fragsrc.nv_addrlen)
{
/* The are the same sizer, return the address comparisson */
return (memcmp(fragsrc.nv_addr, radio->r_fragsrc.nv_addr,
fragsrc.nv_addrlen) == 0);
}
return false;
}
/****************************************************************************
* Name: sixlowpan_compress_ipv6hdr
*
@@ -311,14 +260,15 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
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 */
int ret;
#ifdef CONFIG_NET_6LOWPAN_FRAG
FAR struct sixlowpan_reassbuf_s *reass;
struct netdev_varaddr_s fragsrc;
FAR uint8_t *fragptr; /* Pointer to the fragmentation header */
bool isfrag = false;
bool isfirstfrag = false;
uint16_t fragtag = 0; /* Tag of the fragment */
systime_t elapsed; /* Elapsed time */
int ret;
#endif /* CONFIG_NET_6LOWPAN_FRAG */
/* Get a pointer to the payload following the IEEE802.15.4 frame header(s).
@@ -359,166 +309,119 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
ninfo("FRAG1: fragsize=%d fragtag=%d fragoffset=%d\n",
fragsize, fragtag, fragoffset);
/* Drop any zero length fragments */
if (fragsize == 0)
{
nwarn("WARNING: Dropping zero-length 6LoWPAN fragment\n");
return INPUT_PARTIAL;
}
/* Drop the packet if it cannot fit into the d_buf */
if (fragsize > CONFIG_NET_6LOWPAN_MTU)
{
nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n");
return -ENOSPC;
}
/* Extract the source address from the 'metadata'. */
ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc);
if (ret < 0)
{
nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
return ret;
}
/* Allocate a new reassembly buffer */
reass = sixlowpan_reass_allocate(fragtag, &fragsrc);
if (reass == NULL)
{
nerr("ERROR: Failed to allocate a reassembly buffer\n");
return -ENOMEM;
}
radio->r_dev.d_buf = reass->rb_buf;
radio->r_dev.d_len = 0;
reass->rb_pktlen = fragsize;
/* Indicate the first fragment of the reassembly */
isfirstfrag = true;
isfrag = true;
bptr = reass->rb_buf;
isfirstfrag = true;
isfrag = true;
}
break;
case SIXLOWPAN_DISPATCH_FRAGN:
{
/* Set offset, tag, size. Offset is in units of 8 bytes. */
/* Get offset, tag, size. Offset is in units of 8 bytes. */
fragoffset = fragptr[SIXLOWPAN_FRAG_OFFSET];
fragtag = GETUINT16(fragptr, SIXLOWPAN_FRAG_TAG);
fragsize = GETUINT16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0x07ff;
g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN;
/* Extract the source address from the 'metadata'. */
ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc);
if (ret < 0)
{
nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
return ret;
}
/* Find the existing reassembly buffer with the same tag and source address */
reass = sixlowpan_reass_find(fragtag, &fragsrc);
if (reass == NULL)
{
nerr("ERROR: Failed to find a reassembly buffer for tag=%04x\n",
fragtag);
return -ENOENT;
}
if (fragsize != reass->rb_pktlen)
{
/* The packet is a fragment but its size does not match. */
nwarn("WARNING: Dropping 6LoWPAN packet. Bad fragsize: %u vs &u\n",
fragsize, reass->rb_pktlen);
ret = -EPERM;
goto errout_with_reass;
}
radio->r_dev.d_buf = reass->rb_buf;
radio->r_dev.d_len = 0;
ninfo("FRAGN: fragsize=%d fragtag=%d fragoffset=%d\n",
fragsize, fragtag, fragoffset);
ninfo("FRAGN: r_accumlen=%d paysize=%u fragsize=%u\n",
radio->r_accumlen, iob->io_len - g_frame_hdrlen, fragsize);
ninfo("FRAGN: rb_accumlen=%d paysize=%u fragsize=%u\n",
reass->rb_accumlen, iob->io_len - g_frame_hdrlen, fragsize);
/* Indicate that this frame is a another fragment for reassembly */
isfrag = true;
bptr = g_bitbucket;
isfrag = true;
}
break;
/* Not a fragment */
default:
/* We still need a packet buffer. But in this case, the driver should
* have provided one.
*/
DEBUGASSERT(radio->r_dev.d_buf != NULL);
reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
bptr = reass->rb_buf;
break;
}
/* Check if we are currently reassembling a packet */
bptr = radio->r_dev.d_buf;
if (radio->r_accumlen > 0)
{
/* If reassembly timed out, cancel it */
elapsed = clock_systimer() - radio->r_time;
if (elapsed > NET_6LOWPAN_TIMEOUT)
{
nwarn("WARNING: Reassembly timed out\n");
radio->r_pktlen = 0;
radio->r_accumlen = 0;
}
/* In this case what we expect is that the next frame will hold the
* next FRAGN of the sequence. We have to handle a few exeptional
* cases that we need to handle:
*
* 1. If we are currently reassembling a packet, but have just received
* the first fragment of another packet. We can either ignore it and
* hope to receive the rest of the under-reassembly packet fragments,
* or we can discard the previous packet altogether, and start
* reassembling the new packet. Here we discard the previous packet,
* and start reassembling the new packet.
* 2. The new frame is not a fragment. We should be able to handle this
* case, but we cannot because that would require two packet buffers.
* It could be handled with a more extensive design.
* 3. The fragment came from a different sender. What would this mean?
*
*/
else if (!isfrag)
{
/* Discard the partially assembled packet */
nwarn("WARNING: Non-fragment frame received during reassembly\n");
radio->r_pktlen = 0;
radio->r_accumlen = 0;
}
/* It is a fragment of some kind. Drop any zero length fragments */
else if (fragsize == 0)
{
nwarn("WARNING: Dropping zero-length 6LoWPAN fragment\n");
return INPUT_PARTIAL;
}
/* A non-zero, first fragement received while we are in the middle of
* rassembly. Discard the partially assembled packet and start over.
*/
else if (isfirstfrag)
{
nwarn("WARNING: First fragment frame received during reassembly\n");
radio->r_pktlen = 0;
radio->r_accumlen = 0;
}
/* Verify that this fragment is part of that reassembly sequence */
else if (fragsize != radio->r_pktlen || radio->r_reasstag != fragtag ||
!sixlowpan_compare_fragsrc(radio, metadata))
{
/* The packet is a fragment that does not belong to the packet
* being reassembled or the packet is not a fragment.
*/
nwarn("WARNING: Dropping 6LoWPAN packet that is not a fragment of "
"the packet currently being reassembled\n");
return -EPERM;
}
else
{
/* Looks good. We are currently processing a reassembling sequence
* and we recieved a valid FRAGN fragment. Redirect the header
* uncompression to our bitbucket.
*/
bptr = g_bitbucket;
}
}
/* There is no reassembly in progress. Check if we received a fragment */
else if (isfrag)
{
/* Another case that we have to handle is if a FRAGN fragment of a
* reassembly is received, but we are not currently reassembling a
* packet. I think we have no choice but to drop the packet in this
* case.
*/
if (!isfirstfrag)
{
nwarn("WARNING: FRAGN 6LoWPAN fragment while not reassembling\n");
return -EPERM;
}
/* Drop the packet if it cannot fit into the d_buf */
if (fragsize > CONFIG_NET_6LOWPAN_MTU)
{
nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n");
return -ENOSPC;
}
radio->r_pktlen = fragsize;
radio->r_reasstag = fragtag;
radio->r_time = clock_systimer();
ninfo("Starting reassembly: r_pktlen %u, r_reasstag %d\n",
radio->r_pktlen, radio->r_reasstag);
/* Extract the source address from the 'metadata'. NOTE that the size
* of the source address may be different than our local, destination
* address.
*/
ret = sixlowpan_extract_srcaddr(radio, metadata, &radio->r_fragsrc);
if (ret < 0)
{
nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
return ret;
}
}
#else
bptr = radio->r_dev.d_buf;
#endif /* CONFIG_NET_6LOWPAN_FRAG */
/* Process next dispatch and headers */
@@ -553,7 +456,8 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
/* Unknown or unsupported header */
nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]);
return -ENOSYS;
ret = -ENOSYS;
goto errout_with_reass;
}
#ifdef CONFIG_NET_6LOWPAN_FRAG
@@ -565,7 +469,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
* begin placing the data payload.
*/
radio->r_boffset = g_uncomp_hdrlen;
reass->rb_boffset = g_uncomp_hdrlen;
}
/* No.. is this a subsequent fragment in the same sequence? */
@@ -576,7 +480,7 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
* we began placing payload data.
*/
g_uncomp_hdrlen = radio->r_boffset;
g_uncomp_hdrlen = reass->rb_boffset;
}
#endif /* CONFIG_NET_6LOWPAN_FRAG */
@@ -591,7 +495,8 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
{
nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n",
paysize, CONFIG_NET_6LOWPAN_MTU);
return -ENOSPC;
ret = -ENOSPC;
goto errout_with_reass;
}
/* Sanity-check size of incoming packet to avoid buffer overflow */
@@ -602,14 +507,15 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
nwarn("WARNING: Required buffer size: %u+%u+%u=%u Available=%u\n",
g_uncomp_hdrlen, (fragoffset << 3), paysize,
reqsize, CONFIG_NET_6LOWPAN_MTU);
return -ENOMEM;
ret = -ENOMEM;
goto errout_with_reass;
}
memcpy(radio->r_dev.d_buf + g_uncomp_hdrlen + (fragoffset << 3),
fptr + g_frame_hdrlen, paysize);
#ifdef CONFIG_NET_6LOWPAN_FRAG
/* Update radio->r_accumlen if the frame is a fragment, radio->r_pktlen
/* Update reass->rb_accumlen if the frame is a fragment, reass->rb_pktlen
* otherwise.
*/
@@ -621,36 +527,49 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
* bytes at the end. We must be liberal in what we accept.
*/
radio->r_accumlen = g_uncomp_hdrlen + (fragoffset << 3) + paysize;
reass->rb_accumlen = g_uncomp_hdrlen + (fragoffset << 3) + paysize;
}
else
{
radio->r_pktlen = paysize + g_uncomp_hdrlen;
reass->rb_pktlen = paysize + g_uncomp_hdrlen;
}
/* If we have a full IP packet in sixlowpan_buf, deliver it to
* the IP stack
*/
ninfo("r_accumlen=%d r_pktlen=%d paysize=%d\n",
radio->r_accumlen, radio->r_pktlen, paysize);
ninfo("rb_accumlen=%d rb_pktlen=%d paysize=%d\n",
reass->rb_accumlen, reass->rb_pktlen, paysize);
if (radio->r_accumlen == 0 || radio->r_accumlen >= radio->r_pktlen)
if (reass->rb_accumlen == 0 || reass->rb_accumlen >= reass->rb_pktlen)
{
ninfo("IP packet ready (length %d)\n", radio->r_pktlen);
ninfo("IP packet ready (length %d)\n", reass->rb_pktlen);
radio->r_dev.d_len = radio->r_pktlen;
radio->r_pktlen = 0;
radio->r_accumlen = 0;
radio->r_dev.d_buf = reass->rb_buf;
radio->r_dev.d_len = reass->rb_pktlen;
reass->rb_active = false;
reass->rb_pktlen = 0;
reass->rb_accumlen = 0;
return INPUT_COMPLETE;
}
radio->r_dev.d_buf = NULL;
radio->r_dev.d_len = 0;
return INPUT_PARTIAL;
errout_with_reass:
sixlowpan_reass_free(reass);
return ret;
#else
/* Deliver the packet to the IP stack */
radio->r_dev.d_len = paysize + g_uncomp_hdrlen;
return INPUT_COMPLETE;
errout_with_reass:
return ret;
#endif /* CONFIG_NET_6LOWPAN_FRAG */
}
@@ -670,6 +589,11 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
static int sixlowpan_dispatch(FAR struct radio_driver_s *radio)
{
#ifdef CONFIG_NET_6LOWPAN_FRAG
FAR struct sixlowpan_reassbuf_s *reass;
#endif
int ret;
sixlowpan_dumpbuffer("Incoming packet",
(FAR const uint8_t *)IPv6BUF(&radio->r_dev),
radio->r_dev.d_len);
@@ -691,7 +615,17 @@ static int sixlowpan_dispatch(FAR struct radio_driver_s *radio)
* be set to zero. Oddly, ipv6_input() will return OK in this case.
*/
return ipv6_input(&radio->r_dev);
ret = ipv6_input(&radio->r_dev);
#ifdef CONFIG_NET_6LOWPAN_FRAG
/* Free the reassemby buffer */
reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
DEBUGASSERT(reass != NULL);
sixlowpan_reass_free(reass);
#endif
return ret;
}
/****************************************************************************
+109 -2
View File
@@ -115,8 +115,13 @@
/* Sucessful return values from header compression logic */
#define COMPRESS_HDR_INLINE 0 /* L2 header not compressed */
#define COMPRESS_HDR_ELIDED 1 /* L2 header compressed */
#define COMPRESS_HDR_INLINE 0 /* L2 header not compressed */
#define COMPRESS_HDR_ELIDED 1 /* L2 header compressed */
/* Memory Pools *************************************************************/
#define REASS_POOL_PREALLOCATED 0
#define REASS_POOL_DYNAMIC 1
/* Debug ********************************************************************/
@@ -657,5 +662,107 @@ int sixlowpan_extract_destaddr(FAR struct radio_driver_s *radio,
FAR const void *metadata,
FAR struct netdev_varaddr_s *destaddr);
/****************************************************************************
* Name: sixlowpan_reass_initialize
*
* Description:
* This function initializes the reassembly buffer allocator. This
* function must be called early in the initialization sequence before
* any radios begin operation.
*
* Called only once during network initialization.
*
* Inputs:
* None
*
* Return Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_FRAG
void sixlowpan_reass_initialize(void);
#endif /* CONFIG_NET_6LOWPAN_FRAG */
/****************************************************************************
* Name: sixlowpan_reass_allocate
*
* Description:
* The sixlowpan_reass_allocate function will get a free reassembly buffer
* structure for use by 6LoWPAN.
*
* This function will first attempt to allocate from the g_free_reass
* list. If that the list is empty, then the reassembly buffer structure
* will be allocated from the dynamic memory pool.
*
* Inputs:
* reasstag - The reassembly tag for subsequent lookup.
* fragsrc - The source address of the fragment.
*
* Return Value:
* A reference to the allocated reass structure. All fields used by the
* reasembly logic have been zeroed. On a failure to allocate, NULL is
* returned.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_FRAG
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_allocate(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc);
#endif /* CONFIG_NET_6LOWPAN_FRAG */
/****************************************************************************
* Name: sixlowpan_reass_find
*
* Description:
* Find a previously allocated, active reassembly buffer with the specified
* reassembly tag.
*
* Inputs:
* reasstag - The reassembly tag to match.
* fragsrc - The source address of the fragment.
*
* Return Value:
* A reference to the matching reass structure.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_FRAG
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_find(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc);
#endif /* CONFIG_NET_6LOWPAN_FRAG */
/****************************************************************************
* Name: sixlowpan_reass_free
*
* Description:
* The sixlowpan_reass_free function will return a reass structure
* to the free list of messages if it was a pre-allocated reass
* structure. If the reass structure was allocated dynamically it will
* be deallocated.
*
* Inputs:
* reass - reass structure to free
*
* Return Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_FRAG
void sixlowpan_reass_free(FAR struct sixlowpan_reassbuf_s *reass);
#endif /* CONFIG_NET_6LOWPAN_FRAG */
#endif /* CONFIG_NET_6LOWPAN */
#endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */
+458
View File
@@ -0,0 +1,458 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_reassbuf.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <semaphore.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/clock.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mm/iob.h>
#include "sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN_FRAG
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Re-assembly timeout in clock ticks */
#define NET_6LOWPAN_TIMEOUT SEC2TICK(CONFIG_NET_6LOWPAN_MAXAGE)
/****************************************************************************
* Private Data
****************************************************************************/
/* The g_free_reass is a list of reassembly buffer structures that are available for
* general use. The number of messages in this list is a system configuration
* item. Protected only by the network lock.
*/
static FAR struct sixlowpan_reassbuf_s *g_free_reass;
/* This is a list of active, allocated reassemby buffers */
static FAR struct sixlowpan_reassbuf_s *g_active_reass;
/* Pool of pre-allocated reassembly buffer stuctures */
static struct sixlowpan_reassbuf_s g_metadata_pool[CONFIG_NET_6LOWPAN_NREASSBUF];
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_compare_fragsrc
*
* Description:
* Check if the fragment that we just received is from the same source as
* the previosly received fragements.
*
* Input Parameters:
* radio - Radio network device driver state instance
* fragsrc - The source address of the fragment.
*
* Returned Value:
* true if the sources are the same.
*
****************************************************************************/
static bool sixlowpan_compare_fragsrc(FAR struct sixlowpan_reassbuf_s *reass,
FAR const struct netdev_varaddr_s *fragsrc)
{
/* The addresses cannot match if they are not the same size */
if (fragsrc->nv_addrlen == reass->rb_fragsrc.nv_addrlen)
{
/* The are the same sizer, return the address comparisson */
return (memcmp(fragsrc->nv_addr, reass->rb_fragsrc.nv_addr,
fragsrc->nv_addrlen) == 0);
}
return false;
}
/****************************************************************************
* Name: sixlowpan_reass_expire
*
* Description:
* Free all expired or inactive reassembly buffers.
*
* Inputs:
* None
*
* Return Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void sixlowpan_reass_expire(void)
{
FAR struct sixlowpan_reassbuf_s *reass;
FAR struct sixlowpan_reassbuf_s *next;
systime_t elapsed;
/* If reassembly timed out, cancel it */
for (reass = g_active_reass; reass != NULL; reass = next)
{
/* Needed if 'reass' is freed */
next = reass->rb_flink;
/* Free any inactive reassembly buffers. This is done because the life
* the reassembly buffer is not cerain.
*/
if (!reass->rb_active)
{
sixlowpan_reass_free(reass);
}
else
{
/* Get the elpased time of the reassembly */
elapsed = clock_systimer() - reass->rb_time;
/* If the reassembly has expired, then free the reassembly buffer */
if (elapsed > NET_6LOWPAN_TIMEOUT)
{
nwarn("WARNING: Reassembly timed out\n");
sixlowpan_reass_free(reass);
}
}
}
}
/****************************************************************************
* Name: sixlowpan_remove_active
*
* Description:
* Remove a reassembly buffer from the active reassembly buffer list.
*
* Inputs:
* reass - The reassembly buffer to be removed.
*
* Return Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void sixlowpan_remove_active(FAR struct sixlowpan_reassbuf_s *reass)
{
FAR struct sixlowpan_reassbuf_s *curr;
FAR struct sixlowpan_reassbuf_s *prev;
/* Find the reassembly buffer in the list of active reassembly buffers */
for (prev = NULL, curr = g_active_reass;
curr != NULL && curr != reass;
prev = curr, curr = curr->rb_flink)
{
}
/* Did we find it? */
if (curr != NULL)
{
/* Yes.. remove it from the active reassembly buffer list */
if (prev == NULL)
{
g_active_reass = reass->rb_flink;
}
else
{
prev->rb_flink = reass->rb_flink;
}
}
reass->rb_flink = NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_reass_initialize
*
* Description:
* This function initializes the reassembly buffer allocator. This
* function must be called early in the initialization sequence before
* any radios begin operation.
*
* Called only once during network initialization.
*
* Inputs:
* None
*
* Return Value:
* None
*
****************************************************************************/
void sixlowpan_reass_initialize(void)
{
FAR struct sixlowpan_reassbuf_s *reass;
int i;
/* Initialize g_free_reass, the list of reassembly buffer structures that are
* available for allocation.
*/
g_free_reass = NULL;
for (i = 0, reass = g_metadata_pool;
i < CONFIG_NET_6LOWPAN_NREASSBUF;
i++, reass++)
{
/* Add the next meta data structure from the pool to the list of
* general structures.
*/
reass->rb_flink = g_free_reass;
g_free_reass = reass;
}
}
/****************************************************************************
* Name: sixlowpan_reass_allocate
*
* Description:
* The sixlowpan_reass_allocate function will get a free reassembly buffer
* structure for use by 6LoWPAN.
*
* This function will first attempt to allocate from the g_free_reass
* list. If that the list is empty, then the reassembly buffer structure
* will be allocated from the dynamic memory pool.
*
* Inputs:
* reasstag - The reassembly tag for subsequent lookup.
* fragsrc - The source address of the fragment.
*
* Return Value:
* A reference to the allocated reass structure. All fields used by the
* reasembly logic have been zeroed. On a failure to allocate, NULL is
* returned.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_allocate(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc)
{
FAR struct sixlowpan_reassbuf_s *reass;
uint8_t pool;
/* First, removed any expired or inactive reassembly buffers. This might
* free up a pre-allocated buffer for this allocation.
*/
sixlowpan_reass_expire();
/* Now, try the free list first */
if (g_free_reass != NULL)
{
reass = g_free_reass;
g_free_reass = reass->rb_flink;
pool = REASS_POOL_PREALLOCATED;
}
else
{
#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC
reass = NULL;
#else
/* If we cannot get a reassembly buffer instance from the free list, then we
* will have to allocate one from the kernal memory pool.
*/
reass = (FAR struct sixlowpan_reassbuf_s *)
kmm_malloc((sizeof (struct sixlowpan_reassbuf_s)));
pool = REASS_POOL_DYNAMIC;
#endif
}
/* We have successfully allocated memory from some source? */
if (reass != NULL)
{
/* Zero and tag the allocated reassembly buffer structure. */
memset(reass, 0, sizeof(struct sixlowpan_reassbuf_s));
memcpy(&reass->rb_fragsrc, fragsrc, sizeof(struct netdev_varaddr_s));
reass->rb_pool = pool;
reass->rb_active = true;
reass->rb_reasstag = reasstag;
reass->rb_time = clock_systimer();
/* Add the reassembly buffer to the list of active reassembly buffers */
reass->rb_flink = g_active_reass;
g_active_reass = reass;
}
return reass;
}
/****************************************************************************
* Name: sixlowpan_reass_find
*
* Description:
* Find a previously allocated, active reassembly buffer with the specified
* reassembly tag.
*
* Inputs:
* reasstag - The reassembly tag to match.
* fragsrc - The source address of the fragment.
*
* Return Value:
* A reference to the matching reass structure.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_find(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc)
{
FAR struct sixlowpan_reassbuf_s *reass;
/* First, removed any expired or inactive reassembly buffers (we don't want
* to return old reassembly buffer with the same tag)
*/
sixlowpan_reass_expire();
/* Now search for the matching reassembly buffer in the remainng, active
* reassembly buffers.
*/
for (reass = g_active_reass; reass != NULL; reass = reass->rb_flink)
{
/* In order to be a match, it must have the same reassembly tag as
* well as source address (different sources might use the same
* reassembly tag).
*/
if (reass->rb_reasstag == reasstag &&
sixlowpan_compare_fragsrc(reass, fragsrc))
{
return reass;
}
}
/* Not found */
return NULL;
}
/****************************************************************************
* Name: sixlowpan_reass_free
*
* Description:
* The sixlowpan_reass_free function will return a reass structure
* to the free list of messages if it was a pre-allocated reass
* structure. If the reass structure was allocated dynamically it will
* be deallocated.
*
* Inputs:
* reass - reass structure to free
*
* Return Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
void sixlowpan_reass_free(FAR struct sixlowpan_reassbuf_s *reass)
{
/* First, remove the reassembly buffer from the list of active reassembly
* buffers.
*/
sixlowpan_remove_active(reass);
/* If this is a pre-allocated reassembly buffer structure, then just put it back
* in the free list.
*/
if (reass->rb_pool == REASS_POOL_PREALLOCATED)
{
reass->rb_flink = g_free_reass;
g_free_reass = reass;
}
else
{
#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC
DEBUGPANIC();
#else
DEBUGASSERT(reass->rb_pool == REASS_POOL_DYNAMIC);
/* Otherwise, deallocate it. */
sched_kfree(reass);
#endif
}
}
#endif /* CONFIG_NET_6LOWPAN_FRAG */