| /**************************************************************************** |
| * net/sixlowpan/sixlowpan_reassbuf.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <assert.h> |
| #include <debug.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 certain. |
| */ |
| |
| if (!reass->rb_active) |
| { |
| sixlowpan_reass_free(reass); |
| } |
| else |
| { |
| /* Get the elpased time of the reassembly */ |
| |
| elapsed = clock_systime_ticks() - 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_systime_ticks(); |
| |
| /* 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. */ |
| |
| kmm_free(reass); |
| #endif |
| } |
| |
| /* If the reassembly buffer structure was provided by the driver, nothing |
| * needs to be freed. |
| */ |
| } |