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

View File

@ -610,7 +610,17 @@ Configuration sub-directories
unnecessarily busy. There is some prototype code to do just this
in the driver, but does not seem to work.
2017-08-24: There is only a single buffer for reassemblying larger
packets. This could be an important issue for the hub configuration
2017-08-26: There was only a single buffer for reassemblying larger
packets. This could be a problem issue for the hub configuration
which really needs the capability concurrently reassemble multiple
incoming streams.
incoming streams. The design was extended to support multiple
reassembly buffers.
Initial testing shows the same basic behavior as noted before:
The UDP test works and TCP test (usually) works. There are,
however, are errors in reported by the hub in the TCP test.
Occassionally the test will hang when ther server echoes the data
back to the client. These errors are presumably the result of ACKs
from the receiver colliding with frames from the sender.
Needs more investigation.

View File

@ -671,6 +671,7 @@ Configurations
two star endpoints via the hub, the frames are correctly directed
to the hub. However, they are not being forwarded to the other
endpoint.
2017-06-30: The failure to forward is understood: When the star
endpoint sent the IPv6 destination address, the HC06 compression
logic elided the address -- meaning that it could be reconstructed
@ -686,13 +687,16 @@ Configurations
some additional fixes for byte ordering in 16-bit and 64-bit
compressed IPv6 addresses, then all tests are working as expected:
TCP, UDP, Telnet.
2017-08-05: It looks like I have lost one of my Clicker2-STM32 boards.
This means that I will not be able to do any regression testing as
changes are made to the radio interfaces and 6LoWPAN :(
2017-08-24: There is only a single buffer for reassemblying larger
packets. This could be an important issue for the hub configuration
2017-08-26: There was only a single buffer for reassemblying larger
packets. This could be a problem issue for the hub configuration
which really needs the capability concurrently reassemble multiple
incoming streams.
incoming streams. The design was extended to support multiple
reassembly buffers but have not yet been verified on this platform.
nsh:

View File

@ -203,7 +203,8 @@
*/
/* prescaler common to all PLL inputs; will be 1 (XXX source is implicitly
as per comment above HSI) */
* as per comment above HSI)
*/
#define STM32L4_PLLCFG_PLLM RCC_PLLCFG_PLLM(1)

View File

@ -997,7 +997,7 @@ Tickless OS
will have an error of 0.6% and will have inaccuracies that will
effect the time due to long term error build-up.
Using the slow clock clock input, the Tickless support is functional,
Using the slow clock input, the Tickless support is functional,
however, there are inaccuracies in delays. For example,
nsh> sleep 10
@ -1318,7 +1318,7 @@ Configuration sub-directories
mrf24j40-starhub
This configuration implement a hub node in a 6LoWPAN start network.
This configuration implements a hub node in a 6LoWPAN start network.
It is intended for the us the mrf24j40-starpoint configuration with
the clicker2-stm32 configurations. Essentially, the SAME70 Xplained
plays the roll of the hub in the configuration and the clicker2-stm32
@ -1383,10 +1383,11 @@ Configuration sub-directories
No significant functional testing has yet been performed.
2017-08-24: There is only a single buffer for reassemblying larger
packets. This could be an important issue for the hub configuration
2017-08-26: There was only a single buffer for reassemblying larger
packets. This could be a problem issue for the hub configuration
which really needs the capability concurrently reassemble multiple
incoming streams.
incoming streams. The design was extended to support multiple
reassembly buffers but have not yet been verified on this platform.
netnsh:

View File

@ -1956,10 +1956,11 @@ Configuration sub-directories
The SPI signals look clean on the board and the MRF24J40 seems
fully functional.
2017-08-24: There is only a single buffer for reassemblying larger
packets. This could be an important issue for the hub configuration
2017-08-26: There was only a single buffer for reassemblying larger
packets. This could be a problem issue for the hub configuration
which really needs the capability concurrently reassemble multiple
incoming streams.
incoming streams. The design was extended to support multiple
reassembly buffers but additional testing is needed.
mxtxplnd:

View File

@ -127,6 +127,7 @@
#include <nuttx/spi/spi.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include <nuttx/net/sixlowpan.h>
#include <nuttx/wireless/spirit.h>
#include <nuttx/wireless/pktradio.h>
@ -363,6 +364,12 @@ int spirit_hw_initialize(FAR struct spirit_driver_s *dev,
* Private Data
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN
/* One single packet buffer */
static struct sixlowpan_reassbuf_s g_iobuffer;
#endif
/* Spirit radio initialization */
static const struct radio_init_s g_radio_init =
@ -1043,6 +1050,11 @@ static void spirit_receive_work(FAR void *arg)
iob = pktmeta->pm_iob;
pktmeta->pm_iob = NULL;
/* Make sure the our single packet buffer is attached */
priv->radio.r_dev.d_buf = g_iobuffer.rb_buf;
priv->radio.r_dev.d_len = 0;
/* Send the next frame to the network */
wlinfo("Send frame %p to the network: Offset=%u Length=%u\n",
@ -1137,7 +1149,7 @@ static void spirit_interrupt_work(FAR void *arg)
#ifdef CONFIG_SPIRIT_FIFOS
irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0;
/* Discard any RX buffer that might have been allocated */
/* Discard any packet buffer that might have been allocated */
if (priv->rxbuffer != NULL)
{
@ -1281,7 +1293,12 @@ static void spirit_interrupt_work(FAR void *arg)
if (priv->state != DRIVER_STATE_RECEIVING)
{
DEBUGASSERT(priv->state == DRIVER_STATE_IDLE);
/* As a race condition, the TX state, but overriden by concurrent
* RX activity? This assertion here *does* fire:
*
* DEBUGASSERT(priv->state == DRIVER_STATE_IDLE);
*/
priv->state = DRIVER_STATE_RECEIVING;
}
@ -1320,7 +1337,7 @@ static void spirit_interrupt_work(FAR void *arg)
irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0;
/* There should be a RX buffer that was allocated when the data sync
/* There should be a packet buffer that was allocated when the data sync
* interrupt was processed.
*/
@ -1473,7 +1490,7 @@ static void spirit_interrupt_work(FAR void *arg)
wlinfo("RX FIFO almost full\n");
/* There should be a RX buffer that was allocated when the data sync
/* There should be a packet buffer that was allocated when the data sync
* interrupt was processed.
*/
@ -1571,7 +1588,7 @@ static void spirit_interrupt_work(FAR void *arg)
*/
#ifdef CONFIG_SPIRIT_FIFOS
/* Discard any RX buffer that might have been allocated */
/* Discard any packet buffer that might have been allocated */
if (priv->rxbuffer != NULL)
{
@ -1752,6 +1769,12 @@ static void spirit_txpoll_work(FAR void *arg)
net_lock();
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
priv->radio.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
/* Do nothing if the network is not yet UP */
if (!priv->ifup)
@ -2752,7 +2775,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
FAR struct spirit_driver_s *priv;
FAR struct radio_driver_s *radio;
FAR struct net_driver_s *dev;
FAR uint8_t *pktbuf;
int ret;
/* Allocate a driver state structure instance */
@ -2764,16 +2786,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
return -ENOMEM;
}
/* Allocate a packet buffer */
pktbuf = (uint8_t *)kmm_zalloc(CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE);
if (priv == NULL)
{
wlerr("ERROR: Failed to allocate a packet buffer\n");
ret = -ENOMEM;
goto errout_with_alloc;
}
/* Attach the interface, lower driver, and devops */
priv->lower = lower;
@ -2798,7 +2810,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
/* Initialize the common network device fields */
dev = &radio->r_dev;
dev->d_buf = pktbuf; /* Single packet buffer */
dev->d_ifup = spirit_ifup; /* I/F up (new IP address) callback */
dev->d_ifdown = spirit_ifdown; /* I/F down callback */
dev->d_txavail = spirit_txavail; /* New TX data callback */
@ -2839,7 +2850,7 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
if (ret < 0)
{
wlerr("ERROR: Failed to attach interrupt: %d\n", ret);
goto errout_with_pktbuf;
goto errout_with_alloc;
}
/* Enable Radio IRQ */
@ -2850,11 +2861,6 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
errout_with_attach:
(void)lower->attach(lower, NULL, NULL);
errout_with_pktbuf:
#if 0
kmm_free(pktbuf);
#endif
errout_with_alloc:
kmm_free(priv);
return ret;

View File

@ -42,8 +42,6 @@
#include <stdint.h>
#include <nuttx/clock.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154)
@ -76,22 +74,37 @@ struct radiodev_properties_s
* The radio network driver does not use the d_buf packet buffer directly.
* Rather, it uses a list smaller frame buffers.
*
* - The packet fragment data is provided in an IOB in the via the
* - Outgoing frame data is provided in an IOB in the via the
* r_req_data() interface method each time that the radio needs to
* send more data. The length of the frame is provided in the io_len
* field of the IOB.
*
* In this case, the d_buf is not used at all and, if fact, may be
* NULL.
* Outgoing frames are generated when the radio network driver calls
* the devif_poll(), devif_timer(), sixlowpan_input(), or
* ieee802154_input() interfaces. In each case, the radio driver must
* provide a working buffer in the d_buf pointer. A special form of
* the packet buffer must be used, struct sixlowpan_reassbuf_s. This
* special for includes appended data for managing reassembly of packets.
*
* - Received frames are provided by radio network driver to the network
* via an IOB parameter in the sixlowpan_input() pr ieee802154_input()
* interface. The length of the frame is io_len.
*
* - 6LoWPAN frames and will be uncompressed and possibly reassembled in
* the d_buf; d_len will hold the size of the reassembled packet.
* Again, the radio network driver must provide an instance of struct
* sixlowpan_reassbuf_s as the packet buffer in the d_buf field. This
* driver-provided data will only be used if the the receive frames are
* not fragmented.
*
* In this case, a d_buf of size CONFIG_NET_6LOWPAN_MTU must be provided.
* - Received 6LoWPAN frames and will be uncompressed and possibly
* reassembled in resassembled the d_buf; d_len will hold the size of
* the reassembled packet.
*
* For fagemented frames, d_buf provided by radio driver will not be
* used. 6LoWPAN must handle mutliple reassemblies from different
* sources simultaneously. To support this, 6LoWPAN will allocate a
* unique reassembly buffer for each active reassembly, based on the
* reassembly tag and source radio address. These reassembly buffers
* are managed entirely by the 6LoWPAN layer.
*
* This is accomplished by "inheriting" the standard 'struct net_driver_s'
* and appending the frame buffer as well as other metadata needed to
@ -103,8 +116,9 @@ struct radiodev_properties_s
* structure. In general, all fields must be set to NULL. In addition:
*
* 1. On a TX poll, the radio network driver should provide its driver
* structure. During the course of the poll, the networking layer may
* generate outgoing frames. These frames will by provided to the MAC
* structure along is (single) reassemby buffer provided at d_buf.
* During the course of the poll, the networking layer may generate
* outgoing frames. These frames will by provided to the radio network
* driver via the req_data() method.
*
* After sending each frame through the radio, the MAC driver must
@ -117,16 +131,17 @@ struct radiodev_properties_s
* payload area of an IOB frame structure. That IOB structure may be
* obtained using the iob_alloc() function.
*
* For 6LoWPAN, the larger dev.d_buf must have a size of at least the
* advertised MTU of the protocol, CONFIG_NET_6LOWPAN_MTU, plus
* CONFIG_NET_GUARDSIZE. If fragmentation is enabled, then the logical
* packet size may be significantly larger than the size of the frame
* buffer. The dev.d_buf is used for de-compressing each frame and
* reassembling any fragmented packets to create the full input packet
* that is provided to the application.
* For 6LoWPAN, fragmented packets will be reassembled using allocated
* reassembly buffers that are managed by the 6LoWPAN layer. The radio
* driver must still provide its (single) reassembly buffer in d_buf;
* that buffer is still used for the case where the packet is not
* fragmented into many frames. In either case, the packet buffer will
* have a size of advertised MTU of the protocol, CONFIG_NET_6LOWPAN_MTU,
* plus CONFIG_NET_GUARDSIZE and some additional overhead for reassembly
* state data.
*
* The MAC driver should then inform the network of the reciptor of a
* frame by calling sixlowpan_input() or ieee802154_input(). That
* The radio network driver should then inform the network of the recipt
* of a frame by calling sixlowpan_input() or ieee802154_input(). That
* single frame (or, perhaps, list of frames) should be provided as
* second argument of that call.
*
@ -167,65 +182,6 @@ struct radio_driver_s
uint8_t r_msdu_handle;
#endif
#if CONFIG_NET_6LOWPAN_FRAG
/* Fragmentation Support *************************************************/
/* Fragmentation is handled frame by frame and requires that certain
* state information be retained from frame to frame.
*/
/* r_dgramtag. Datagram tag to be put in the header of the set of
* fragments. It is used by the recipient to match fragments of the
* same payload.
*
* This is the sender's copy of the tag. It is incremented after each
* fragmented packet is sent so that it will be unique to that
* sequence fragmentation. Its value is then persistent, the values of
* other fragmentation variables are valid on during a single
* fragmentation sequence (while r_accumlen > 0)
*/
uint16_t r_dgramtag;
/* r_reasstag. Each frame in the reassembly has a tag. That tag must
* match the reassembly tag in the fragments being merged.
*
* This is the same tag as r_dgramtag but is saved on the receiving
* side to match all of the fragments of the packet.
*/
uint16_t r_reasstag;
/* r_pktlen. The total length of the IPv6 packet to be re-assembled in
* d_buf. Used to determine when the re-assembly is complete.
*/
uint16_t r_pktlen;
/* The current accumulated length of the packet being received in d_buf.
* Included IPv6 and protocol headers. Currently used only to determine
* there is a fragmentation sequence in progress.
*/
uint16_t r_accumlen;
/* r_boffset. Offset to the beginning of data in d_buf. As each fragment
* is received, data is placed at an appriate offset added to this.
*/
uint16_t r_boffset;
/* The source MAC address of the fragments being merged */
struct netdev_varaddr_s r_fragsrc;
/* That time at which reassembly was started. If the elapsed time
* exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will
* be cancelled.
*/
systime_t r_time;
#endif /* CONFIG_NET_6LOWPAN_FRAG */
/* MAC network driver callback functions **********************************/
/**************************************************************************
* Name: r_get_mhrlen

View File

@ -53,6 +53,10 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/clock.h>
#include <nuttx/net/netdev.h>
#ifdef CONFIG_NET_6LOWPAN
@ -337,6 +341,99 @@
(a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \
(((a)[7] & HTONS(0xff00)) == 0x0000))
/****************************************************************************
* Public Types
****************************************************************************/
/* Fragmentation Support
*
* This structure defines the reassembly buffer. NOTE: The packet buffer
* is needed even in the case where reassembly is disabled.
*/
struct sixlowpan_reassbuf_s
{
/* This is the externally visible packet buffer. This is assigned
* to the driver's d_buf field when the reassembly is complete and
* provides the full reassembly packet to the network.
*/
uint8_t rb_buf[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE];
/* Memory pool used to allocate this reassembly buffer */
uint8_t rb_pool;
/* True if the reassemby buffer is active (set to false when reassembly is
* complete).
*/
bool rb_active;
/* Supports a singly linked list */
FAR struct sixlowpan_reassbuf_s *rb_flink;
#if CONFIG_NET_6LOWPAN_FRAG
/* Fragmentation is handled frame by frame and requires that certain
* state information be retained from frame to frame. That additional
* information follows the externally visible packet buffer.
*/
/* rb_dgramtag. Datagram tag to be put in the header of the set of
* fragments. It is used by the recipient to match fragments of the
* same payload.
*
* This is the sender's copy of the tag. It is incremented after each
* fragmented packet is sent so that it will be unique to that
* sequence fragmentation. Its value is then persistent, the values of
* other fragmentation variables are valid on during a single
* fragmentation sequence (while rb_accumlen > 0)
*/
uint16_t rb_dgramtag;
/* rb_reasstag. Each frame in the reassembly has a tag. That tag must
* match the reassembly tag in the fragments being merged.
*
* This is the same tag as rb_dgramtag but is saved on the receiving
* side to match all of the fragments of the packet.
*/
uint16_t rb_reasstag;
/* rb_pktlen. The total length of the IPv6 packet to be re-assembled in
* d_buf. Used to determine when the re-assembly is complete.
*/
uint16_t rb_pktlen;
/* The current accumulated length of the packet being received in d_buf.
* Included IPv6 and protocol headers. Currently used only to determine
* there is a fragmentation sequence in progress.
*/
uint16_t rb_accumlen;
/* rb_boffset. Offset to the beginning of data in d_buf. As each fragment
* is received, data is placed at an appriate offset added to this.
*/
uint16_t rb_boffset;
/* The source MAC address of the fragments being merged */
struct netdev_varaddr_s rb_fragsrc;
/* That time at which reassembly was started. If the elapsed time
* exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will
* be cancelled.
*/
systime_t rb_time;
#endif /* CONFIG_NET_6LOWPAN_FRAG */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/

View File

@ -447,7 +447,6 @@ uint16_t devif_conn_event(FAR struct net_driver_s *dev, void *pvconn,
* beginning of the list (which will be ignored on this pass)
*/
ninfo("Call event=%p with flags=%04x\n", list->event, flags);
flags = list->event(dev, pvconn, list->priv, flags);
}
@ -511,7 +510,6 @@ uint16_t devif_dev_event(FAR struct net_driver_s *dev, void *pvconn,
* beginning of the list (which will be ignored on this pass)
*/
ninfo("Call event=%p with flags=%04x\n", cb->event, flags);
flags = cb->event(dev, pvconn, cb->priv, flags);
}

View File

@ -67,7 +67,7 @@
void devif_send(struct net_driver_s *dev, const void *buf, int len)
{
DEBUGASSERT(dev && len > 0 && len < NET_DEV_MTU(dev));
DEBUGASSERT(dev != NULL && len > 0 && len < NET_DEV_MTU(dev));
memcpy(dev->d_appdata, buf, len);
dev->d_sndlen = len;

View File

@ -51,6 +51,7 @@
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/radiodev.h>
#include <netpacket/ieee802154.h>

View File

@ -64,7 +64,7 @@
#endif
#if defined(CONFIG_NET_TCP)
# define L3_MAXHDRLEN TCP_MAX_HDRLEN
# define L3_MAXHDRLEN TCP_HDRLEN /* Could be up to TCP_MAX_HDRLEN */
#elif defined(CONFIG_NET_UDP)
# define L3_MAXHDRLEN UDP_HDRLEN
#elif defined(CONFIG_NET_ICMPv6)

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

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

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");

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>

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"

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 */

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;
}
/****************************************************************************

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 */

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 */

View File

@ -48,6 +48,7 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/net/netconfig.h>
@ -342,9 +343,12 @@ found:
#endif
/* We must free this TCP connection structure; this connection
* will never be established.
* will never be established. There should only be one reference
* on this connection when we allocated for the connection.
*/
DEBUGASSERT(conn->crefs == 1);
conn->crefs = 0;
tcp_free(conn);
}
else

View File

@ -51,6 +51,7 @@
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/radiodev.h>
@ -137,7 +138,7 @@ struct lo_driver_s
static struct lo_driver_s g_loopback;
#ifdef CONFIG_NET_6LOWPAN
static uint8_t g_iobuffer[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE];
static struct sixlowpan_reassbuf_s g_iobuffer;
#endif
static uint8_t g_eaddr[IEEE802154_EADDRSIZE] =
@ -388,6 +389,12 @@ static int lo_loopback(FAR struct net_driver_s *dev)
#endif
#ifdef CONFIG_NET_6LOWPAN
{
/* Make sure the our single packet buffer is attached */
priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf;
/* Then give the frame to 6LoWPAN */
ret = sixlowpan_input(&priv->lo_radio, iob, (FAR void *)&ind);
}
#endif
@ -459,6 +466,15 @@ static void lo_poll_work(FAR void *arg)
/* Perform the poll */
net_lock();
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
/* Then perform the poll */
(void)devif_timer(&priv->lo_radio.r_dev, lo_loopback);
/* Setup the watchdog poll timer again */
@ -634,6 +650,12 @@ static void lo_txavail_work(FAR void *arg)
{
/* If so, then poll the network for new XMIT data */
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
(void)devif_poll(&priv->lo_radio.r_dev, lo_loopback);
}
@ -1063,9 +1085,6 @@ int ieee8021514_loopback(void)
#endif
#ifdef CONFIG_NETDEV_IOCTL
dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */
#endif
#ifdef CONFIG_NET_6LOWPAN
dev->d_buf = g_iobuffer; /* Attach the IO buffer */
#endif
dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */

View File

@ -224,6 +224,14 @@ static int macnet_req_data(FAR struct radio_driver_s *netdev,
static int macnet_properties(FAR struct radio_driver_s *netdev,
FAR struct radiodev_properties_s *properties);
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN
static struct sixlowpan_reassbuf_s g_iobuffer;
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@ -470,6 +478,12 @@ static int macnet_rxframe(FAR struct mac802154_maccb_s *maccb,
}
else
{
/* Make sure the our single packet buffer is attached */
priv->md_dev.r_dev.d_buf = g_iobuffer.rb_buf;
/* And give the packet to 6LoWPAN */
ret = sixlowpan_input(&priv->md_dev, iob, (FAR void *)ind);
}
}
@ -568,7 +582,13 @@ static void macnet_txpoll_work(FAR void *arg)
net_lock();
/* Perform the poll */
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
priv->md_dev.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
/* Then perform the poll */
(void)devif_timer(&priv->md_dev.r_dev, macnet_txpoll_callback);
@ -836,9 +856,13 @@ static void macnet_txavail_work(FAR void *arg)
if (priv->md_bifup)
{
/* Check if there is room in the hardware to hold another outgoing packet. */
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
/* If so, then poll the network for new XMIT data */
priv->md_dev.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
/* Then poll the network for new XMIT data */
(void)devif_poll(&priv->md_dev.r_dev, macnet_txpoll_callback);
}
@ -1206,9 +1230,6 @@ int mac802154netdev_register(MACHANDLE mac)
FAR struct radio_driver_s *radio;
FAR struct net_driver_s *dev;
FAR struct mac802154_maccb_s *maccb;
#ifdef CONFIG_NET_6LOWPAN
FAR uint8_t *pktbuf;
#endif
int ret;
DEBUGASSERT(mac != NULL);
@ -1224,27 +1245,10 @@ int mac802154netdev_register(MACHANDLE mac)
return -ENOMEM;
}
#ifdef CONFIG_NET_6LOWPAN
/* Allocate a packet buffer (not used by this driver, but needed by the
* upper networking layer)
*/
pktbuf = (FAR uint8_t *)kmm_malloc(CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE);
if (pktbuf == NULL)
{
nerr("ERROR: Failed to allocate the packet buffer\n");
kmm_free(priv);
return -ENOMEM;
}
#endif
/* Initialize the driver structure */
radio = &priv->md_dev;
dev = &radio->r_dev;
#ifdef CONFIG_NET_6LOWPAN
dev->d_buf = pktbuf; /* Single packet buffer */
#endif
dev->d_ifup = macnet_ifup; /* I/F up (new IP address) callback */
dev->d_ifdown = macnet_ifdown; /* I/F down callback */
dev->d_txavail = macnet_txavail; /* New TX data callback */
@ -1297,9 +1301,6 @@ int mac802154netdev_register(MACHANDLE mac)
/* Free memory and return the error */
#ifdef CONFIG_NET_6LOWPAN
kmm_free(pktbuf);
#endif
kmm_free(priv);
return ret;
}

View File

@ -51,6 +51,7 @@
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/radiodev.h>
@ -130,7 +131,9 @@ struct lo_driver_s
****************************************************************************/
static struct lo_driver_s g_loopback;
static uint8_t g_iobuffer[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE];
#ifdef CONFIG_NET_6LOWPAN
static struct sixlowpan_reassbuf_s g_iobuffer;
#endif
static uint8_t g_mac_addr[CONFIG_PKTRADIO_ADDRLEN] =
{
@ -346,6 +349,10 @@ static int lo_loopback(FAR struct net_driver_s *dev)
priv->lo_tail = NULL;
}
/* Make sure the our single packet buffer is attached */
priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf;
/* Return the next frame to the network */
ninfo("Send frame %p to the network: Offset=%u Length=%u\n",
@ -420,6 +427,15 @@ static void lo_poll_work(FAR void *arg)
/* Perform the poll */
net_lock();
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
/* And perform the poll */
(void)devif_timer(&priv->lo_radio.r_dev, lo_loopback);
/* Setup the watchdog poll timer again */
@ -576,6 +592,13 @@ static void lo_txavail_work(FAR void *arg)
if (priv->lo_bifup)
{
/* If so, then poll the network for new XMIT data */
#ifdef CONFIG_NET_6LOWPAN
/* Make sure the our single packet buffer is attached */
priv->lo_radio.r_dev.d_buf = g_iobuffer.rb_buf;
#endif
/* Then perform the poll */
(void)devif_poll(&priv->lo_radio.r_dev, lo_loopback);
}
@ -1009,7 +1032,6 @@ int pktradio_loopback(void)
#ifdef CONFIG_NETDEV_IOCTL
dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */
#endif
dev->d_buf = g_iobuffer; /* Attach the IO buffer */
dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */
/* Set the network mask and advertise our MAC-based IP address */