cde88cabcc
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
457 lines
13 KiB
C
457 lines
13 KiB
C
/****************************************************************************
|
|
* 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 <assert.h>
|
|
#include <errno.h>
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/mm/iob.h>
|
|
|
|
#include "sixlowpan_internal.h"
|
|
|
|
/****************************************************************************
|
|
* 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 structures */
|
|
|
|
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 previously received fragments.
|
|
*
|
|
* 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 size, return the address comparison */
|
|
|
|
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.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned 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;
|
|
clock_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.
|
|
*
|
|
* Input Parameters:
|
|
* reass - The reassembly buffer to be removed.
|
|
*
|
|
* Returned 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.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned 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.
|
|
*
|
|
* Input Parameters:
|
|
* reasstag - The reassembly tag for subsequent lookup.
|
|
* fragsrc - The source address of the fragment.
|
|
*
|
|
* Returned 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 kernel 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.
|
|
*
|
|
* Input Parameters:
|
|
* reasstag - The reassembly tag to match.
|
|
* fragsrc - The source address of the fragment.
|
|
*
|
|
* Returned 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.
|
|
*
|
|
* Input Parameters:
|
|
* reass - reass structure to free
|
|
*
|
|
* Returned 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 if (reass->rb_pool == REASS_POOL_DYNAMIC)
|
|
{
|
|
#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC
|
|
DEBUGPANIC();
|
|
#else
|
|
DEBUGASSERT(reass->rb_pool == REASS_POOL_DYNAMIC);
|
|
|
|
/* Otherwise, deallocate it. */
|
|
|
|
sched_kfree(reass);
|
|
#endif
|
|
}
|
|
|
|
/* If the reassembly buffer structure was provided by the driver, nothing
|
|
* needs to be freed.
|
|
*/
|
|
}
|