mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Merge pull request #14169 from artokin/nanostack_release_12_8_0_to_master
Nanostack release v12.8.0pull/14092/head
						commit
						dc40c47cfa
					
				| 
						 | 
				
			
			@ -96,6 +96,7 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
// RF_PAC
 | 
			
		||||
#define TXPWR                       0x1F
 | 
			
		||||
#define TXPWR_7                     (7 << 0)
 | 
			
		||||
#define TXPWR_11                    (11 << 0)
 | 
			
		||||
#define TXPWR_0                     (0 << 0)
 | 
			
		||||
#define TXPWR_31                    (31 << 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,9 +30,24 @@
 | 
			
		|||
#include <Timer.h>
 | 
			
		||||
#include "Timeout.h"
 | 
			
		||||
#include "SPI.h"
 | 
			
		||||
#include "platform/mbed_version.h"
 | 
			
		||||
 | 
			
		||||
#define TRACE_GROUP "AtRF"
 | 
			
		||||
 | 
			
		||||
#if (MBED_VERSION > MBED_ENCODE_VERSION(6, 0, 0))
 | 
			
		||||
/* Mbed OS 6.0 introduces support for chrono time management */
 | 
			
		||||
using namespace std::chrono_literals;
 | 
			
		||||
#define ATMEL_RF_TIME_65MS  65ms
 | 
			
		||||
#define ATMEL_RF_TIME_1US   1us
 | 
			
		||||
#define ATMEL_RF_ATTACH(timer_ref, signal_ref, timeout_ref) timer_ref.attach(signal_ref, timeout_ref)
 | 
			
		||||
#define ATMEL_RF_DRIVER_CHRONO_SUPPORTED
 | 
			
		||||
#else
 | 
			
		||||
#define ATMEL_RF_TIME_65MS  65000
 | 
			
		||||
#define ATMEL_RF_TIME_1US   1
 | 
			
		||||
 | 
			
		||||
#define ATMEL_RF_ATTACH(timer_ref, signal_ref, timeout_ref) timer_ref.attach_us(signal_ref, timeout_ref)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define RF_MTU_15_4_2011    127
 | 
			
		||||
#define RF_MTU_15_4G_2012   2047
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,8 +179,6 @@ static const phy_device_channel_page_s phy_channel_pages[] = {
 | 
			
		|||
    { CHANNEL_PAGE_0, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using namespace std::chrono_literals;
 | 
			
		||||
 | 
			
		||||
using namespace mbed;
 | 
			
		||||
using namespace rtos;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -198,7 +211,11 @@ static Se2435Pins *se2435_pa_pins = NULL;
 | 
			
		|||
 | 
			
		||||
static uint32_t rf_get_timestamp(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef ATMEL_RF_DRIVER_CHRONO_SUPPORTED
 | 
			
		||||
    return (uint32_t)rf->tx_timer.elapsed_time().count();
 | 
			
		||||
#else
 | 
			
		||||
    return (uint32_t)rf->tx_timer.read_us();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rf_lock(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -487,7 +504,7 @@ static void rf_init_registers(rf_modules_e module)
 | 
			
		|||
            // Set low frequency offset bit
 | 
			
		||||
            rf_write_bbc_register_field(BBC_OFDMC, module, LFO, 0);
 | 
			
		||||
            // Configure using bandwidth option
 | 
			
		||||
            rf_configure_by_ofdm_bandwidth_option(4, 300000, module);
 | 
			
		||||
            rf_configure_by_ofdm_bandwidth_option(phy_current_config.ofdm_option, phy_current_config.datarate, module);
 | 
			
		||||
            // Set Gain control settings
 | 
			
		||||
            rf_write_rf_register_field(RF_AGCC, module, AVGS, AVGS_8_SAMPLES);
 | 
			
		||||
            rf_write_rf_register_field(RF_AGCC, module, AGCI, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -501,8 +518,8 @@ static void rf_init_registers(rf_modules_e module)
 | 
			
		|||
        se2435_pa_pins->ANT_SEL = 0;
 | 
			
		||||
        // Enable external front end with configuration 3
 | 
			
		||||
        rf_write_rf_register_field(RF_PADFE, module, PADFE, RF_FEMODE3);
 | 
			
		||||
        // Output power at 900MHz: 0 dBm with FSK/QPSK, less than -5 dBm with OFDM
 | 
			
		||||
        rf_tx_power = TXPWR_11;
 | 
			
		||||
        // Output power at 900MHz: -4 dBm with FSK/QPSK, less than -10 dBm with OFDM
 | 
			
		||||
        rf_tx_power = TXPWR_7;
 | 
			
		||||
    }
 | 
			
		||||
    // Set TX output power
 | 
			
		||||
    rf_write_rf_register_field(RF_PAC, module, TXPWR, rf_tx_power);
 | 
			
		||||
| 
						 | 
				
			
			@ -566,17 +583,21 @@ static int8_t rf_start_csma_ca(uint8_t *data_ptr, uint16_t data_length, uint8_t
 | 
			
		|||
    mac_tx_handle = tx_handle;
 | 
			
		||||
 | 
			
		||||
    if (tx_time) {
 | 
			
		||||
#ifdef ATMEL_RF_DRIVER_CHRONO_SUPPORTED
 | 
			
		||||
        std::chrono::microseconds backoff_time(tx_time - rf_get_timestamp());
 | 
			
		||||
#else
 | 
			
		||||
        uint32_t backoff_time = tx_time - rf_get_timestamp();
 | 
			
		||||
#endif
 | 
			
		||||
        // Max. time to TX can be 65ms, otherwise time has passed already -> send immediately
 | 
			
		||||
        if (backoff_time <= 65ms) {
 | 
			
		||||
            rf->cca_timer.attach(rf_csma_ca_timer_signal, backoff_time);
 | 
			
		||||
        if (backoff_time <= ATMEL_RF_TIME_65MS) {
 | 
			
		||||
            ATMEL_RF_ATTACH(rf->cca_timer, rf_csma_ca_timer_signal, backoff_time);
 | 
			
		||||
            TEST_CSMA_STARTED
 | 
			
		||||
            rf_unlock();
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Short timeout to start CCA immediately.
 | 
			
		||||
    rf->cca_timer.attach(rf_csma_ca_timer_signal, 1us);
 | 
			
		||||
    ATMEL_RF_ATTACH(rf->cca_timer, rf_csma_ca_timer_signal, ATMEL_RF_TIME_1US);
 | 
			
		||||
    TEST_CSMA_STARTED
 | 
			
		||||
    rf_unlock();
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -609,12 +630,16 @@ static void rf_handle_cca_ed_done(void)
 | 
			
		|||
    if (cca_prepare_status == PHY_RESTART_CSMA) {
 | 
			
		||||
        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_OK, 0, 0);
 | 
			
		||||
        if (tx_time) {
 | 
			
		||||
#ifdef ATMEL_RF_DRIVER_CHRONO_SUPPORTED
 | 
			
		||||
            std::chrono::microseconds backoff_time(tx_time - rf_get_timestamp());
 | 
			
		||||
#else
 | 
			
		||||
            uint32_t backoff_time = tx_time - rf_get_timestamp();
 | 
			
		||||
#endif
 | 
			
		||||
            // Max. time to TX can be 65ms, otherwise time has passed already -> send immediately
 | 
			
		||||
            if (backoff_time > 65ms) {
 | 
			
		||||
                backoff_time = 1us;
 | 
			
		||||
            if (backoff_time > ATMEL_RF_TIME_65MS) {
 | 
			
		||||
                backoff_time = ATMEL_RF_TIME_1US;
 | 
			
		||||
            }
 | 
			
		||||
            rf->cca_timer.attach(rf_csma_ca_timer_signal, backoff_time);
 | 
			
		||||
            ATMEL_RF_ATTACH(rf->cca_timer, rf_csma_ca_timer_signal, backoff_time);
 | 
			
		||||
            TEST_CSMA_STARTED
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -996,7 +1021,11 @@ static uint32_t rf_backup_timer_start(uint16_t bytes, uint32_t time_us)
 | 
			
		|||
        time_us = (uint32_t)(8000000 / phy_current_config.datarate) * bytes + PACKET_PROCESSING_TIME;
 | 
			
		||||
    }
 | 
			
		||||
    // Using cal_timer as backup timer
 | 
			
		||||
#ifdef ATMEL_RF_DRIVER_CHRONO_SUPPORTED
 | 
			
		||||
    rf->cal_timer.attach(rf_backup_timer_signal, std::chrono::microseconds(time_us));
 | 
			
		||||
#else
 | 
			
		||||
    rf->cal_timer.attach_us(rf_backup_timer_signal, time_us);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return (rf_get_timestamp() + time_us);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@ target_sources(mbed-nanostack-libservice
 | 
			
		|||
        source/libip4string/stoip4.c
 | 
			
		||||
        source/libip6string/stoip6.c
 | 
			
		||||
        source/nsdynmemLIB/nsdynmemLIB.c
 | 
			
		||||
        source/nsdynmemtracker/nsdynmem_tracker_lib.c
 | 
			
		||||
        source/nvmHelper/ns_nvm_helper.c
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ source/libip6string/ip6tos.c \
 | 
			
		|||
source/libip6string/stoip6.c \
 | 
			
		||||
source/libList/ns_list.c \
 | 
			
		||||
source/nsdynmemLIB/nsdynmemLIB.c \
 | 
			
		||||
source/nsdynmemtracker/nsdynmem_tracker_lib.c \
 | 
			
		||||
source/nvmHelper/ns_nvm_helper.c \
 | 
			
		||||
 | 
			
		||||
LIB := libservice.a
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,9 @@ extern "C" {
 | 
			
		|||
typedef size_t ns_mem_block_size_t; //external interface unsigned heap block size type
 | 
			
		||||
typedef size_t ns_mem_heap_size_t; //total heap size type.
 | 
			
		||||
 | 
			
		||||
// Can be used to enable tracking of dynamic memory allocations
 | 
			
		||||
#include "nsdynmem_tracker.h"
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \enum heap_fail_t
 | 
			
		||||
 * \brief Dynamically heap system failure call back event types.
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +67,6 @@ typedef struct mem_stat_t {
 | 
			
		|||
    uint32_t heap_alloc_fail_cnt;               /**< Counter for Heap allocation fail. */
 | 
			
		||||
} mem_stat_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct ns_mem_book ns_mem_book_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +101,9 @@ extern int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_siz
 | 
			
		|||
  * \return 0, Free OK
 | 
			
		||||
  * \return <0, Free Fail
 | 
			
		||||
  */
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED!=1
 | 
			
		||||
extern void ns_dyn_mem_free(void *heap_ptr);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Allocate temporary data.
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +115,9 @@ extern void ns_dyn_mem_free(void *heap_ptr);
 | 
			
		|||
  * \return 0, Allocate Fail
 | 
			
		||||
  * \return >0, Pointer to allocated data sector.
 | 
			
		||||
  */
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED!=1
 | 
			
		||||
extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Allocate long period data.
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +129,9 @@ extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
 | 
			
		|||
  * \return 0, Allocate Fail
 | 
			
		||||
  * \return >0, Pointer to allocated data sector.
 | 
			
		||||
  */
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED!=1
 | 
			
		||||
extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020 ARM Limited. All rights reserved.
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 * Licensed 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file nsdynmem_tracker.h
 | 
			
		||||
 * \brief Dynamical Memory Tracker definitions to override the default NS dynamic memory functionality
 | 
			
		||||
 * Provides tracking and tracing of dynamic memory blocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NSDYNMEM_TRACKER_H_
 | 
			
		||||
#define NSDYNMEM_TRACKER_H_
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED==1
 | 
			
		||||
 | 
			
		||||
#define ns_dyn_mem_free(block) ns_dyn_mem_tracker_dyn_mem_free(block, __func__, __LINE__)
 | 
			
		||||
#define ns_dyn_mem_temporary_alloc(alloc_size) ns_dyn_mem_tracker_dyn_mem_temporary_alloc(alloc_size, __func__, __LINE__)
 | 
			
		||||
#define ns_dyn_mem_alloc(alloc_size) ns_dyn_mem_tracker_dyn_mem_alloc(alloc_size, __func__, __LINE__)
 | 
			
		||||
 | 
			
		||||
void *ns_dyn_mem_tracker_dyn_mem_alloc(ns_mem_heap_size_t alloc_size, const char *function, uint32_t line);
 | 
			
		||||
void *ns_dyn_mem_tracker_dyn_mem_temporary_alloc(ns_mem_heap_size_t alloc_size, const char *function, uint32_t line);
 | 
			
		||||
void ns_dyn_mem_tracker_dyn_mem_free(void *block, const char *function, uint32_t line);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* NSDYNMEM_TRACKER_H_ */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,104 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020 ARM Limited. All rights reserved.
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 * Licensed 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file nsdynmem_tracker_lib.h
 | 
			
		||||
 * \brief Dynamical Memory Tracker library API
 | 
			
		||||
 * Provides tracking and tracing of dynamic memory blocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NSDYNMEM_TRACKER_LIB_H_
 | 
			
		||||
#define NSDYNMEM_TRACKER_LIB_H_
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED==1
 | 
			
		||||
 | 
			
		||||
// Memory block structure with caller information
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_mem_blocks_s {
 | 
			
		||||
    void *block;                   /**< Allocated memory block */
 | 
			
		||||
    void *caller_addr;             /**< Caller address */
 | 
			
		||||
    uint32_t size;                 /**< Allocation size */
 | 
			
		||||
    uint32_t total_size;           /**< Total allocation size for all allocations */
 | 
			
		||||
    uint32_t lifetime;             /**< Memory block lifetime in steps (e.g. seconds) */
 | 
			
		||||
    uint32_t ref_count;            /**< Reference count */
 | 
			
		||||
    const char *function;          /**< Caller function */
 | 
			
		||||
    uint16_t line;                 /**< Caller line in module */
 | 
			
		||||
    bool permanent : 1;            /**< Permanent memory block */
 | 
			
		||||
    bool permanent_printed : 1;    /**< Permanent memory block printed */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_mem_blocks_t;
 | 
			
		||||
 | 
			
		||||
// Extended memory block structure that is used if same caller allocates multiple memory blocks
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_mem_blocks_ext_s {
 | 
			
		||||
    void *block;                   /**< Allocated memory block */
 | 
			
		||||
    void *caller_addr;             /**< Caller address */
 | 
			
		||||
    uint32_t size;                 /**< Allocation size */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_mem_blocks_ext_t;
 | 
			
		||||
 | 
			
		||||
// Allocator information structure
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_allocators_s {
 | 
			
		||||
    void *caller_addr;             /**< Caller address */
 | 
			
		||||
    uint32_t alloc_count;          /**< Number of allocations */
 | 
			
		||||
    uint32_t total_memory;         /**< Total memory used by allocations */
 | 
			
		||||
    uint32_t min_lifetime;         /**< Shortest lifetime among the allocations */
 | 
			
		||||
    const char *function;          /**< Function name string */
 | 
			
		||||
    uint16_t line;                 /**< Module line */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_allocators_t;
 | 
			
		||||
 | 
			
		||||
// Memory block array allocator / array size increase allocator
 | 
			
		||||
typedef ns_dyn_mem_tracker_lib_mem_blocks_t *ns_dyn_mem_tracker_lib_alloc_mem_blocks(ns_dyn_mem_tracker_lib_mem_blocks_t *blocks, uint16_t *mem_blocks_count);
 | 
			
		||||
// Extended memory block array allocator / array size increase allocator
 | 
			
		||||
typedef ns_dyn_mem_tracker_lib_mem_blocks_ext_t *ns_dyn_mem_tracker_lib_alloc_mem_blocks_ext(ns_dyn_mem_tracker_lib_mem_blocks_ext_t *blocks, uint32_t *mem_blocks_count);
 | 
			
		||||
// Extended memory block array index hash function to get memory block (allocation/search start) index from block address
 | 
			
		||||
typedef uint32_t ns_dyn_mem_tracker_lib_mem_block_index_hash(void *block, uint32_t ext_mem_blocks_count);
 | 
			
		||||
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_conf_s {
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_t *mem_blocks;                    /**< Memory blocks array, if NULL calls allocator on init */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_ext_t *ext_mem_blocks;            /**< Extended memory blocks array, if NULL calls allocator on init */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *top_allocators;                /**< Top allocators array */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *permanent_allocators;          /**< Permanent allocators */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *to_permanent_allocators;       /**< To permanent allocators */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *max_snap_shot_allocators;      /**< Snap shot of maximum memory used by allocators */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_alloc_mem_blocks *alloc_mem_blocks;          /**< Memory block array allocator / array size increase allocator */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_alloc_mem_blocks_ext *ext_alloc_mem_blocks;  /**< Extended memory block array allocator / array size increase allocator */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_block_index_hash *block_index_hash;      /**< Hash function to get memory block index from block address */
 | 
			
		||||
    uint32_t allocated_memory;                                          /**< Currently allocated memory */
 | 
			
		||||
    uint16_t mem_blocks_count;                                          /**< Number of entries in memory blocks array */
 | 
			
		||||
    uint32_t ext_mem_blocks_count;                                      /**< Number of entries in extended memory blocks array */
 | 
			
		||||
    uint16_t last_mem_block_index;                                      /**< Last memory block in memory blocks array */
 | 
			
		||||
    uint16_t top_allocators_count;                                      /**< Top allocators array count */
 | 
			
		||||
    uint16_t permanent_allocators_count;                                /**< Permanent allocators array count */
 | 
			
		||||
    uint16_t to_permanent_allocators_count;                             /**< To permanent allocators array count */
 | 
			
		||||
    uint16_t max_snap_shot_allocators_count;                            /**< Snap shot of maximum memory used by allocators array count */
 | 
			
		||||
    uint16_t to_permanent_steps_count;                                  /**< How many steps before moving block to permanent allocators list */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_conf_t;
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_alloc(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block, uint32_t alloc_size);
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_free(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block);
 | 
			
		||||
void ns_dyn_mem_tracker_lib_step(ns_dyn_mem_tracker_lib_conf_t *conf);
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_allocator_lists_update(ns_dyn_mem_tracker_lib_conf_t *conf);
 | 
			
		||||
void ns_dyn_mem_tracker_lib_max_snap_shot_update(ns_dyn_mem_tracker_lib_conf_t *conf);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* NSDYNMEM_TRACKER_LIB_H_ */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,11 @@
 | 
			
		|||
{
 | 
			
		||||
    "name": "nanostack-libservice",
 | 
			
		||||
    "macros": ["NSDYNMEM_TRACKER_ENABLED=MBED_CONF_NANOSTACK_LIBSERVICE_NSDYNMEM_TRACKER_ENABLED"],
 | 
			
		||||
    "config": {
 | 
			
		||||
        "present": 1
 | 
			
		||||
        "present": 1,
 | 
			
		||||
        "nsdynmem-tracker-enabled": {
 | 
			
		||||
            "help": "Use to enable dynamic memory tracker",
 | 
			
		||||
            "value": 0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#undef NSDYNMEM_TRACKER_ENABLED
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
#include "platform/arm_hal_interrupt.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +48,7 @@ struct ns_mem_book {
 | 
			
		|||
    ns_mem_heap_size_t temporary_alloc_heap_limit;   /* Amount of reserved heap temporary alloc can't exceed */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static mem_stat_t default_stats;
 | 
			
		||||
static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use
 | 
			
		||||
 | 
			
		||||
// size of a hole_t in our word units
 | 
			
		||||
| 
						 | 
				
			
			@ -162,12 +164,14 @@ ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size,
 | 
			
		|||
    ns_list_init(&book->holes_list);
 | 
			
		||||
    ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main[0]));
 | 
			
		||||
 | 
			
		||||
    book->mem_stat_info_ptr = info_ptr;
 | 
			
		||||
    //RESET Memory by Hea Len
 | 
			
		||||
    if (info_ptr) {
 | 
			
		||||
        memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
 | 
			
		||||
        book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
 | 
			
		||||
        book->mem_stat_info_ptr = info_ptr;
 | 
			
		||||
    } else {
 | 
			
		||||
        book->mem_stat_info_ptr = &default_stats;
 | 
			
		||||
    }
 | 
			
		||||
    //RESET Memory by Heap Len
 | 
			
		||||
    memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
 | 
			
		||||
    book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
 | 
			
		||||
    book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
 | 
			
		||||
#endif
 | 
			
		||||
    //There really is no support to standard malloc in this library anymore
 | 
			
		||||
| 
						 | 
				
			
			@ -234,9 +238,7 @@ int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t
 | 
			
		|||
    // adjust total heap size with new hole
 | 
			
		||||
    book->heap_size += region_size;
 | 
			
		||||
 | 
			
		||||
    if (book->mem_stat_info_ptr) {
 | 
			
		||||
        book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
 | 
			
		||||
    }
 | 
			
		||||
    book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
 | 
			
		||||
 | 
			
		||||
    // adjust temporary allocation limits to match new heap
 | 
			
		||||
    book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
 | 
			
		||||
| 
						 | 
				
			
			@ -265,8 +267,8 @@ int ns_mem_set_temporary_alloc_free_heap_threshold(ns_mem_book_t *book, uint8_t
 | 
			
		|||
#ifndef STANDARD_MALLOC
 | 
			
		||||
    ns_mem_heap_size_t heap_limit = 0;
 | 
			
		||||
 | 
			
		||||
    if (!book || !book->mem_stat_info_ptr) {
 | 
			
		||||
        // no book or mem_stats
 | 
			
		||||
    if (!book) {
 | 
			
		||||
        // no book
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -304,25 +306,25 @@ extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_
 | 
			
		|||
#ifndef STANDARD_MALLOC
 | 
			
		||||
static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size)
 | 
			
		||||
{
 | 
			
		||||
    if (mem_stat_info_ptr) {
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case DEV_HEAP_ALLOC_OK:
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_alloc_cnt++;
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_allocated_bytes += size;
 | 
			
		||||
                if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
 | 
			
		||||
                    mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
 | 
			
		||||
                }
 | 
			
		||||
                mem_stat_info_ptr->heap_alloc_total_bytes += size;
 | 
			
		||||
                break;
 | 
			
		||||
            case DEV_HEAP_ALLOC_FAIL:
 | 
			
		||||
                mem_stat_info_ptr->heap_alloc_fail_cnt++;
 | 
			
		||||
                break;
 | 
			
		||||
            case DEV_HEAP_FREE:
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_alloc_cnt--;
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case DEV_HEAP_ALLOC_OK:
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_alloc_cnt++;
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_allocated_bytes += size;
 | 
			
		||||
            if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
 | 
			
		||||
            }
 | 
			
		||||
            mem_stat_info_ptr->heap_alloc_total_bytes += size;
 | 
			
		||||
            break;
 | 
			
		||||
        case DEV_HEAP_ALLOC_FAIL:
 | 
			
		||||
            mem_stat_info_ptr->heap_alloc_fail_cnt++;
 | 
			
		||||
            break;
 | 
			
		||||
        case DEV_HEAP_FREE:
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_alloc_cnt--;
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes)
 | 
			
		||||
| 
						 | 
				
			
			@ -363,7 +365,7 @@ static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_
 | 
			
		|||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (book->mem_stat_info_ptr && direction == 1) {
 | 
			
		||||
    if (direction == 1) {
 | 
			
		||||
        if (book->mem_stat_info_ptr->heap_sector_allocated_bytes > book->temporary_alloc_heap_limit) {
 | 
			
		||||
            /* Not enough heap for temporary memory allocation */
 | 
			
		||||
            dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -441,14 +443,14 @@ static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_
 | 
			
		|||
    block_ptr[1 + data_size] = data_size;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
    if (book->mem_stat_info_ptr) {
 | 
			
		||||
        if (block_ptr) {
 | 
			
		||||
            //Update Allocate OK
 | 
			
		||||
            dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t));
 | 
			
		||||
        } else {
 | 
			
		||||
            //Update Allocate Fail, second parameter is used for stats
 | 
			
		||||
            dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (block_ptr) {
 | 
			
		||||
        //Update Allocate OK
 | 
			
		||||
        dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t));
 | 
			
		||||
    } else {
 | 
			
		||||
        //Update Allocate Fail, second parameter is used for stats
 | 
			
		||||
        dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
 | 
			
		||||
    }
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -619,10 +621,8 @@ void ns_mem_free(ns_mem_book_t *book, void *block)
 | 
			
		|||
            heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
 | 
			
		||||
        } else {
 | 
			
		||||
            ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size);
 | 
			
		||||
            if (book->mem_stat_info_ptr) {
 | 
			
		||||
                //Update Free Counter
 | 
			
		||||
                dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
 | 
			
		||||
            }
 | 
			
		||||
            //Update Free Counter
 | 
			
		||||
            dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,480 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020 ARM Limited. All rights reserved.
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 * Licensed 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "ns_types.h"
 | 
			
		||||
#include "nsdynmem_tracker_lib.h"
 | 
			
		||||
#include "platform/arm_hal_interrupt.h"
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED==1
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint16_t *index);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_caller_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, uint16_t *caller_index);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint16_t *block_index);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint32_t start_index, uint32_t *free_index);
 | 
			
		||||
static void ns_dyn_mem_tracker_lib_permanent_printed_value_set(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, bool new_value);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint32_t start_index, uint32_t *block_index);
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_alloc(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block, uint32_t alloc_size)
 | 
			
		||||
{
 | 
			
		||||
    // Allocation failed
 | 
			
		||||
    if (block == NULL) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    // If dynamic memory blocks are not set, calls allocator
 | 
			
		||||
    if (conf->mem_blocks == NULL) {
 | 
			
		||||
        conf->mem_blocks = conf->alloc_mem_blocks(conf->mem_blocks, &conf->mem_blocks_count);
 | 
			
		||||
        if (conf->mem_blocks == NULL) {
 | 
			
		||||
            platform_exit_critical();
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t caller_index = 0;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_caller_index(conf, caller_addr, &caller_index) >= 0) {
 | 
			
		||||
        if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
            conf->ext_mem_blocks = conf->ext_alloc_mem_blocks(conf->ext_mem_blocks, &conf->ext_mem_blocks_count);
 | 
			
		||||
            if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
                platform_exit_critical();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint32_t free_index = 0;
 | 
			
		||||
        uint32_t start_index = 0;
 | 
			
		||||
        if (conf->block_index_hash != NULL) {
 | 
			
		||||
            start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
 | 
			
		||||
        }
 | 
			
		||||
        if (ns_dyn_mem_tracker_lib_ext_find_free_index(conf, start_index, &free_index) < 0) {
 | 
			
		||||
            conf->ext_mem_blocks = conf->ext_alloc_mem_blocks(conf->ext_mem_blocks, &conf->ext_mem_blocks_count);
 | 
			
		||||
            if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
                platform_exit_critical();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            if (conf->block_index_hash != NULL) {
 | 
			
		||||
                start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
 | 
			
		||||
            }
 | 
			
		||||
            if (ns_dyn_mem_tracker_lib_ext_find_free_index(conf, start_index, &free_index) < 0) {
 | 
			
		||||
                platform_exit_critical();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Updates memory blocks array entry
 | 
			
		||||
        conf->mem_blocks[caller_index].ref_count++;
 | 
			
		||||
        conf->mem_blocks[caller_index].total_size += alloc_size;
 | 
			
		||||
        conf->mem_blocks[caller_index].lifetime = 0;
 | 
			
		||||
        conf->mem_blocks[caller_index].permanent = false;
 | 
			
		||||
        conf->mem_blocks[caller_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
        conf->ext_mem_blocks[free_index].block = block;
 | 
			
		||||
        conf->ext_mem_blocks[free_index].caller_addr = caller_addr;
 | 
			
		||||
        conf->ext_mem_blocks[free_index].size = alloc_size;
 | 
			
		||||
 | 
			
		||||
        conf->allocated_memory += alloc_size;
 | 
			
		||||
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t free_index = 0;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_free_index(conf, &free_index) < 0) {
 | 
			
		||||
        conf->mem_blocks = conf->alloc_mem_blocks(conf->mem_blocks, &conf->mem_blocks_count);
 | 
			
		||||
        if (conf->mem_blocks == NULL || (ns_dyn_mem_tracker_lib_find_free_index(conf, &free_index) < 0)) {
 | 
			
		||||
            platform_exit_critical();
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    conf->mem_blocks[free_index].block = block;
 | 
			
		||||
    conf->mem_blocks[free_index].caller_addr = caller_addr;
 | 
			
		||||
    conf->mem_blocks[free_index].size = alloc_size;
 | 
			
		||||
    conf->mem_blocks[free_index].total_size = alloc_size;
 | 
			
		||||
    conf->mem_blocks[free_index].lifetime = 0;
 | 
			
		||||
    conf->mem_blocks[free_index].ref_count = 1;
 | 
			
		||||
    conf->mem_blocks[free_index].function = function;
 | 
			
		||||
    conf->mem_blocks[free_index].line = line;
 | 
			
		||||
    conf->mem_blocks[free_index].permanent = false;
 | 
			
		||||
    conf->mem_blocks[free_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
    if (free_index > conf->last_mem_block_index) {
 | 
			
		||||
        conf->last_mem_block_index = free_index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    conf->allocated_memory += alloc_size;
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_free(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block)
 | 
			
		||||
{
 | 
			
		||||
    (void) function;
 | 
			
		||||
    (void) line;
 | 
			
		||||
    (void) caller_addr;
 | 
			
		||||
 | 
			
		||||
    // No memory block or no allocations made
 | 
			
		||||
    if (block == NULL || conf->mem_blocks == NULL) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    uint16_t block_index = 0;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_block_index(conf, block, &block_index) >= 0) {
 | 
			
		||||
        // If last block for allocator clears the allocator
 | 
			
		||||
        if (conf->mem_blocks[block_index].ref_count <= 1) {
 | 
			
		||||
            conf->mem_blocks[block_index].ref_count = 0;
 | 
			
		||||
            conf->mem_blocks[block_index].caller_addr = NULL;
 | 
			
		||||
            conf->mem_blocks[block_index].total_size = 0;
 | 
			
		||||
            conf->mem_blocks[block_index].function = NULL;
 | 
			
		||||
            conf->mem_blocks[block_index].line = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Other blocks exists
 | 
			
		||||
            conf->mem_blocks[block_index].ref_count--;
 | 
			
		||||
            conf->mem_blocks[block_index].total_size -= conf->mem_blocks[block_index].size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        conf->allocated_memory -= conf->mem_blocks[block_index].size;
 | 
			
		||||
 | 
			
		||||
        // Clears block specific fields
 | 
			
		||||
        conf->mem_blocks[block_index].block = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].size = 0;
 | 
			
		||||
        // Resets lifetime and permanent settings
 | 
			
		||||
        conf->mem_blocks[block_index].lifetime = 0;
 | 
			
		||||
        conf->mem_blocks[block_index].permanent = false;
 | 
			
		||||
        conf->mem_blocks[block_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t ext_block_index = 0;
 | 
			
		||||
    uint32_t start_index = 0;
 | 
			
		||||
    if (conf->block_index_hash != NULL) {
 | 
			
		||||
        start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
 | 
			
		||||
    }
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_ext_find_block_index(conf, block, start_index, &ext_block_index) < 0) {
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void *ext_caller_addr = conf->ext_mem_blocks[ext_block_index].caller_addr;
 | 
			
		||||
 | 
			
		||||
    uint16_t caller_index;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_caller_index(conf, ext_caller_addr, &caller_index) < 0) {
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    conf->mem_blocks[caller_index].ref_count--;
 | 
			
		||||
    conf->mem_blocks[caller_index].total_size -= conf->ext_mem_blocks[ext_block_index].size;
 | 
			
		||||
 | 
			
		||||
    conf->allocated_memory -= conf->ext_mem_blocks[ext_block_index].size;
 | 
			
		||||
 | 
			
		||||
    // Clears extended block
 | 
			
		||||
    conf->ext_mem_blocks[ext_block_index].block = NULL;
 | 
			
		||||
    conf->ext_mem_blocks[ext_block_index].caller_addr = NULL;
 | 
			
		||||
    conf->ext_mem_blocks[ext_block_index].size = 0;
 | 
			
		||||
 | 
			
		||||
    // Resets lifetime and permanent settings
 | 
			
		||||
    conf->mem_blocks[block_index].lifetime = 0;
 | 
			
		||||
    conf->mem_blocks[block_index].permanent = false;
 | 
			
		||||
    conf->mem_blocks[block_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
    // If last block for allocator clears the allocator
 | 
			
		||||
    if (conf->mem_blocks[block_index].ref_count == 0) {
 | 
			
		||||
        conf->mem_blocks[block_index].block = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].caller_addr = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].size = 0;
 | 
			
		||||
        conf->mem_blocks[block_index].total_size = 0;
 | 
			
		||||
        conf->mem_blocks[block_index].function = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].line = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ns_dyn_mem_tracker_lib_step(ns_dyn_mem_tracker_lib_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    if (conf->mem_blocks_count != 0) {
 | 
			
		||||
        for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
            if (conf->mem_blocks[index].block != NULL) {
 | 
			
		||||
                conf->mem_blocks[index].lifetime++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_allocator_lists_update(ns_dyn_mem_tracker_lib_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_t *blocks = conf->mem_blocks;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *top_allocators = conf->top_allocators;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *permanent_allocators = conf->permanent_allocators;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *to_permanent_allocators = conf->to_permanent_allocators;
 | 
			
		||||
 | 
			
		||||
    uint16_t top_allocators_count = conf->top_allocators_count;
 | 
			
		||||
    uint16_t permanent_allocators_count = conf->permanent_allocators_count;
 | 
			
		||||
    uint16_t to_permanent_allocators_count = conf->to_permanent_allocators_count;
 | 
			
		||||
 | 
			
		||||
    memset(top_allocators, 0, top_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
    memset(permanent_allocators, 0, permanent_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
    memset(to_permanent_allocators, 0, to_permanent_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
 | 
			
		||||
    // Maximum set as permanent in one go
 | 
			
		||||
    uint8_t to_permanent_count = 0;
 | 
			
		||||
 | 
			
		||||
    // Maximum to print of permanent entries
 | 
			
		||||
    uint8_t permanent_count = 0;
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (blocks[index].block != NULL) {
 | 
			
		||||
            void *caller_addr = blocks[index].caller_addr;
 | 
			
		||||
 | 
			
		||||
            // Checks if caller address has already been counted
 | 
			
		||||
            bool next = false;
 | 
			
		||||
            for (uint32_t list_index = 0; list_index < top_allocators_count; list_index++) {
 | 
			
		||||
                if (top_allocators[list_index].caller_addr == caller_addr) {
 | 
			
		||||
                    next = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (next) {
 | 
			
		||||
                // Already on list, continue
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Checks whether all reference are marked permanent
 | 
			
		||||
            if (blocks[index].permanent) {
 | 
			
		||||
                if (!blocks[index].permanent_printed && permanent_count < permanent_allocators_count) {
 | 
			
		||||
                    permanent_allocators[permanent_count].caller_addr = caller_addr;
 | 
			
		||||
                    permanent_allocators[permanent_count].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    permanent_allocators[permanent_count].total_memory = blocks[index].total_size;
 | 
			
		||||
                    permanent_allocators[permanent_count].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    permanent_allocators[permanent_count].function = blocks[index].function;
 | 
			
		||||
                    permanent_allocators[permanent_count].line = blocks[index].line;
 | 
			
		||||
 | 
			
		||||
                    permanent_count++;
 | 
			
		||||
                    blocks[index].permanent_printed = true;
 | 
			
		||||
                }
 | 
			
		||||
                continue;
 | 
			
		||||
            } else {
 | 
			
		||||
                // Checks whether lifetime threshold has been reached, traces and skips
 | 
			
		||||
                if (blocks[index].lifetime > conf->to_permanent_steps_count && to_permanent_count < to_permanent_allocators_count) {
 | 
			
		||||
                    blocks[index].permanent = true;
 | 
			
		||||
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].caller_addr = caller_addr;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].total_memory = blocks[index].total_size;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].function = blocks[index].function;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].line = blocks[index].line;
 | 
			
		||||
 | 
			
		||||
                    to_permanent_count++;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add to list if allocation count is larger than entry on the list
 | 
			
		||||
            for (uint16_t list_index = 0; list_index < top_allocators_count; list_index++) {
 | 
			
		||||
                if (blocks[index].ref_count >= top_allocators[list_index].alloc_count) {
 | 
			
		||||
                    if (list_index != (top_allocators_count - 1)) {
 | 
			
		||||
                        uint8_t index_count = (top_allocators_count - list_index - 1);
 | 
			
		||||
                        uint32_t size = index_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t);
 | 
			
		||||
                        memmove(&top_allocators[list_index + 1], &top_allocators[list_index], size);
 | 
			
		||||
                    }
 | 
			
		||||
                    top_allocators[list_index].caller_addr = caller_addr;
 | 
			
		||||
                    top_allocators[list_index].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    top_allocators[list_index].total_memory = blocks[index].total_size;
 | 
			
		||||
                    top_allocators[list_index].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    top_allocators[list_index].function = blocks[index].function;
 | 
			
		||||
                    top_allocators[list_index].line = blocks[index].line;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (permanent_count < permanent_allocators_count) {
 | 
			
		||||
        ns_dyn_mem_tracker_lib_permanent_printed_value_set(conf, NULL, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ns_dyn_mem_tracker_lib_max_snap_shot_update(ns_dyn_mem_tracker_lib_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_t *blocks = conf->mem_blocks;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *max_snap_shot_allocators = conf->max_snap_shot_allocators;
 | 
			
		||||
 | 
			
		||||
    uint16_t max_snap_shot_allocators_count = conf->max_snap_shot_allocators_count;
 | 
			
		||||
 | 
			
		||||
    memset(max_snap_shot_allocators, 0, max_snap_shot_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (blocks[index].block != NULL) {
 | 
			
		||||
            void *caller_addr = blocks[index].caller_addr;
 | 
			
		||||
 | 
			
		||||
            // Checks if caller address has already been counted
 | 
			
		||||
            bool next = false;
 | 
			
		||||
            for (uint16_t list_index = 0; list_index < max_snap_shot_allocators_count; list_index++) {
 | 
			
		||||
                if (max_snap_shot_allocators[list_index].caller_addr == caller_addr) {
 | 
			
		||||
                    next = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (next) {
 | 
			
		||||
                // Already on list, continue
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add to list if allocation count is larger than entry on the list
 | 
			
		||||
            for (uint16_t list_index = 0; list_index < max_snap_shot_allocators_count; list_index++) {
 | 
			
		||||
                if (blocks[index].total_size >= max_snap_shot_allocators[list_index].total_memory) {
 | 
			
		||||
                    if (list_index != (max_snap_shot_allocators_count - 1)) {
 | 
			
		||||
                        uint8_t index_count = (max_snap_shot_allocators_count - list_index - 1);
 | 
			
		||||
                        uint32_t size = index_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t);
 | 
			
		||||
                        memmove(&max_snap_shot_allocators[list_index + 1], &max_snap_shot_allocators[list_index], size);
 | 
			
		||||
                    }
 | 
			
		||||
                    max_snap_shot_allocators[list_index].caller_addr = blocks[index].caller_addr;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].total_memory = blocks[index].total_size;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].function = blocks[index].function;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].line = blocks[index].line;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ns_dyn_mem_tracker_lib_permanent_printed_value_set(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, bool new_value)
 | 
			
		||||
{
 | 
			
		||||
    /* Search for all the references to the caller address from the allocation info and
 | 
			
		||||
       set block permanent value */
 | 
			
		||||
    for (uint16_t search_index = 0; search_index <= conf->last_mem_block_index; search_index++) {
 | 
			
		||||
        if (caller_addr == NULL || conf->mem_blocks[search_index].caller_addr == caller_addr) {
 | 
			
		||||
            conf->mem_blocks[search_index].permanent_printed = new_value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint16_t *free_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint16_t index = 0; index < conf->mem_blocks_count; index++) {
 | 
			
		||||
        if (conf->mem_blocks[index].caller_addr == NULL) {
 | 
			
		||||
            *free_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_caller_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, uint16_t *caller_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint16_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (conf->mem_blocks[index].caller_addr == caller_addr) {
 | 
			
		||||
            *caller_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint16_t *block_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint16_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (conf->mem_blocks[index].block == block) {
 | 
			
		||||
            *block_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint32_t start_index, uint32_t *free_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint32_t index = start_index; index < conf->ext_mem_blocks_count; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].caller_addr == NULL) {
 | 
			
		||||
            *free_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (start_index == 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index < start_index; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].caller_addr == NULL) {
 | 
			
		||||
            *free_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint32_t start_index, uint32_t *block_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint32_t index = start_index; index < conf->ext_mem_blocks_count; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].block == block) {
 | 
			
		||||
            *block_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (start_index == 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index < start_index; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].block == block) {
 | 
			
		||||
            *block_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -400,12 +400,12 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold)
 | 
			
		|||
    CHECK(info.heap_sector_alloc_cnt == 0);
 | 
			
		||||
    free(heap);
 | 
			
		||||
 | 
			
		||||
    // Test6, feature is disabled if info is not set
 | 
			
		||||
    // Test6, feature is disabled if info is coming anyway
 | 
			
		||||
    heap = (uint8_t *)malloc(size);
 | 
			
		||||
    CHECK(NULL != heap);
 | 
			
		||||
    ns_dyn_mem_init(heap, size, &heap_fail_callback, NULL);
 | 
			
		||||
    ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 0);
 | 
			
		||||
    CHECK(ret_val == -1);
 | 
			
		||||
    CHECK(ret_val == 0);
 | 
			
		||||
    CHECK(!heap_have_failed());
 | 
			
		||||
    free(heap);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,7 +66,9 @@ static NS_LIST_DEFINE(socket_list, internal_socket_t, link);
 | 
			
		|||
static uint8_t max_handshakes = MAX_ONGOING_HANDSHAKES;
 | 
			
		||||
static uint8_t max_sessions = MAX_SECURE_SESSION_COUNT;
 | 
			
		||||
 | 
			
		||||
#ifdef COAP_SECURITY_AVAILABLE
 | 
			
		||||
static void timer_cb(void *param);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void recv_sckt_msg(void *cb_res);
 | 
			
		||||
#ifdef COAP_SECURITY_AVAILABLE
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +124,7 @@ static secure_session_t *secure_session_find_by_timer_id(int8_t timer_id)
 | 
			
		|||
    return this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef COAP_SECURITY_AVAILABLE
 | 
			
		||||
static bool is_secure_session_valid(secure_session_t *session)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +134,7 @@ static bool is_secure_session_valid(secure_session_t *session)
 | 
			
		|||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void secure_session_delete(secure_session_t *this)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -164,6 +168,7 @@ static int8_t virtual_socket_id_allocate()
 | 
			
		|||
 | 
			
		||||
static secure_session_t *secure_session_create(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port, SecureConnectionMode secure_mode)
 | 
			
		||||
{
 | 
			
		||||
    (void) secure_mode;
 | 
			
		||||
    uint8_t handshakes = 0;
 | 
			
		||||
    if (!address_ptr) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -493,6 +498,7 @@ static int secure_session_recvfrom(int8_t socket_id, unsigned char *buf, size_t
 | 
			
		|||
 * TODO - might be better to use an event timer in conjunction with
 | 
			
		||||
 * CoAP tasklet
 | 
			
		||||
 */
 | 
			
		||||
#ifdef COAP_SECURITY_AVAILABLE
 | 
			
		||||
static void timer_cb(void *param)
 | 
			
		||||
{
 | 
			
		||||
    secure_session_t *sec = param;
 | 
			
		||||
| 
						 | 
				
			
			@ -524,6 +530,7 @@ static void timer_cb(void *param)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef COAP_SECURITY_AVAILABLE
 | 
			
		||||
static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
#if !defined(MBEDTLS_CONFIG_FILE)
 | 
			
		||||
#include "mbedtls/config.h"
 | 
			
		||||
#else
 | 
			
		||||
// cppcheck-suppress preprocessorErrorDirective
 | 
			
		||||
#include MBEDTLS_CONFIG_FILE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,6 +109,7 @@ int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_s *), uin
 | 
			
		|||
    event_tmp->data.receiver = new->id;
 | 
			
		||||
    event_tmp->data.sender = 0;
 | 
			
		||||
    event_tmp->data.event_type = init_event_type;
 | 
			
		||||
    event_tmp->data.event_id = 0;
 | 
			
		||||
    event_tmp->data.event_data = 0;
 | 
			
		||||
    event_core_write(event_tmp);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +198,9 @@ void event_core_free_push(arm_event_storage_t *free)
 | 
			
		|||
            timer_sys_event_free(free);
 | 
			
		||||
            break;
 | 
			
		||||
        case ARM_LIB_EVENT_USER:
 | 
			
		||||
            // *INDENT-OFF*
 | 
			
		||||
            // No need set state to UNQUEUED - we forget about it.
 | 
			
		||||
            // *INDENT-ON*
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -132,6 +132,9 @@ typedef struct fhss_ws_configuration {
 | 
			
		|||
    /** Wi-SUN specific unicast channel mask */
 | 
			
		||||
    uint32_t unicast_channel_mask[8];
 | 
			
		||||
 | 
			
		||||
    /** Channel mask size */
 | 
			
		||||
    uint16_t channel_mask_size;
 | 
			
		||||
 | 
			
		||||
    /** Vendor defined channel function. */
 | 
			
		||||
    fhss_vendor_defined_cf *vendor_defined_cf;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,7 +78,7 @@ typedef enum {
 | 
			
		|||
} mlme_primitive;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \struct mac_description_storage_size_t
 | 
			
		||||
 * \struct mac_description_storage_size_s
 | 
			
		||||
 * \brief Container for MAC storage sizes.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct mac_description_storage_size_s {
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +305,7 @@ struct mac_api_s {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \struct mac_statistics_t
 | 
			
		||||
 * \struct mac_statistics_s
 | 
			
		||||
 * \brief MAC statistics structure.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct mac_statistics_s {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ typedef enum arm_library_event_type_e {
 | 
			
		|||
#define SOCKET_BIND_DONE                    SOCKET_CONNECT_DONE      /**< Backward compatibility */
 | 
			
		||||
#define SOCKET_BIND_FAIL                    SOCKET_CONNECT_FAIL      /**< Backward compatibility */
 | 
			
		||||
#define SOCKET_BIND_AUTH_FAIL               SOCKET_CONNECT_AUTH_FAIL /**< Backward compatibility */
 | 
			
		||||
/* @} */
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/** Network security levels. */
 | 
			
		||||
typedef enum net_security_t {
 | 
			
		||||
| 
						 | 
				
			
			@ -1228,3 +1228,4 @@ extern const cca_threshold_table_s *arm_nwk_get_cca_threshold_table(int8_t inter
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* NET_INTERFACE_H_ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,7 +89,7 @@ typedef enum pana_client_nvm_update_process_t {
 | 
			
		|||
} pana_client_nvm_update_process_t;
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \struct wpan_nvm_params_t
 | 
			
		||||
 * \struct wpan_nvm_params
 | 
			
		||||
 * \brief Network nvm parameters.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct wpan_nvm_params {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ extern "C" {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \enum net_host_mode_t
 | 
			
		||||
 * \enum net_host_mode
 | 
			
		||||
 * \brief Sleepy host states.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum net_host_mode {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ typedef struct ns_mdns *ns_mdns_t;  /**< Instance */
 | 
			
		|||
typedef struct ns_mdns_service *ns_mdns_service_t;  /**< Service instance */
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \struct ns_mdns_service_param_t
 | 
			
		||||
 * \struct ns_mdns_service_param
 | 
			
		||||
 * \brief Structure for mDNS service parameters
 | 
			
		||||
 */
 | 
			
		||||
typedef struct ns_mdns_service_param {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,6 +73,7 @@ typedef struct nwk_stats_t {
 | 
			
		|||
    /* MAC */
 | 
			
		||||
    uint16_t adapt_layer_tx_queue_size; /**< Adaptation layer direct TX queue size. */
 | 
			
		||||
    uint16_t adapt_layer_tx_queue_peak; /**< Adaptation layer direct TX queue size peak. */
 | 
			
		||||
    uint32_t adapt_layer_tx_congestion_drop; /**< Adaptation layer direct TX randon early detection drop packet. */
 | 
			
		||||
} nwk_stats_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,7 @@ extern "C" {
 | 
			
		|||
#define ARM_AES_MBEDTLS_CONTEXT_MIN 1 /**</ event loop use only */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** AES context */
 | 
			
		||||
typedef struct arm_aes_context arm_aes_context_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -175,6 +175,25 @@ typedef enum {
 | 
			
		|||
    MODULATION_INDEX_UNDEFINED  ///< Modulation index undefined
 | 
			
		||||
} phy_modulation_index_e;
 | 
			
		||||
 | 
			
		||||
/** OFDM option */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    OFDM_OPTION_1 = 1,      ///< OFDM option 1
 | 
			
		||||
    OFDM_OPTION_2 = 2,      ///< OFDM option 2
 | 
			
		||||
    OFDM_OPTION_3 = 3,      ///< OFDM option 3
 | 
			
		||||
    OFDM_OPTION_4 = 4       ///< OFDM option 4
 | 
			
		||||
} phy_ofdm_option_e;
 | 
			
		||||
 | 
			
		||||
/** Modulation and coding scheme (OFDM) */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    OFDM_MCS_0 = 0,         ///< OFDM MCS 0
 | 
			
		||||
    OFDM_MCS_1 = 1,         ///< OFDM MCS 1
 | 
			
		||||
    OFDM_MCS_2 = 2,         ///< OFDM MCS 2
 | 
			
		||||
    OFDM_MCS_3 = 3,         ///< OFDM MCS 3
 | 
			
		||||
    OFDM_MCS_4 = 4,         ///< OFDM MCS 4
 | 
			
		||||
    OFDM_MCS_5 = 5,         ///< OFDM MCS 5
 | 
			
		||||
    OFDM_MCS_6 = 6          ///< OFDM MCS 6
 | 
			
		||||
} phy_ofdm_mcs_e;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief enum phy_802_15_4_mode_t IEEE 802.15.4 mode
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -192,6 +211,9 @@ typedef struct phy_rf_channel_configuration_s {
 | 
			
		|||
    uint16_t number_of_channels;                ///< Number of channels
 | 
			
		||||
    phy_modulation_e modulation;                ///< Modulation scheme
 | 
			
		||||
    phy_modulation_index_e modulation_index;    ///< Modulation index
 | 
			
		||||
    bool fec;                                   ///< Forward error correction, true - enabled, false - disabled
 | 
			
		||||
    phy_ofdm_option_e ofdm_option;              ///< OFDM option
 | 
			
		||||
    phy_ofdm_mcs_e ofdm_mcs;                    ///< OFDM modulation and coding scheme
 | 
			
		||||
} phy_rf_channel_configuration_s;
 | 
			
		||||
 | 
			
		||||
/** Channel page configuration */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -196,7 +196,7 @@ typedef struct socket_callback_t {
 | 
			
		|||
} socket_callback_t;
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \struct ns_msghdr_t
 | 
			
		||||
 * \struct ns_msghdr
 | 
			
		||||
 * \brief Normal IP socket message structure for socket_recvmsg() and socket_sendmsg().
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +211,7 @@ typedef struct ns_msghdr {
 | 
			
		|||
} ns_msghdr_t;
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \struct ns_cmsghdr_t
 | 
			
		||||
 * \struct ns_cmsghdr
 | 
			
		||||
 * \brief Control messages.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct ns_cmsghdr {
 | 
			
		||||
| 
						 | 
				
			
			@ -242,7 +242,7 @@ typedef struct ns_cmsghdr {
 | 
			
		|||
#define NS_MSG_LEGACY0  0x4000
 | 
			
		||||
///@}
 | 
			
		||||
/*!
 | 
			
		||||
 * \struct ns_in6_pktinfo_t
 | 
			
		||||
 * \struct ns_in6_pktinfo
 | 
			
		||||
 * \brief IPv6 packet info which is used for socket_recvmsg() socket_sendmsg().
 | 
			
		||||
 */
 | 
			
		||||
typedef struct ns_in6_pktinfo {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,7 +96,8 @@ int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id);
 | 
			
		|||
#define BBR_GUA_ROUTE             0x0002 /**< More specific route is added for GUA prefix */
 | 
			
		||||
#define BBR_BB_WAIT               0x0004 /**< Wait backbone availability before starting Wi-SUN network */
 | 
			
		||||
#define BBR_DEFAULT_ROUTE         0x0008 /**< Add default route parameter to DIO */
 | 
			
		||||
#define BBR_REQUIRE_DAO_REFRESH   0x0010 /**< Do not increment PAN version number when active forces DAO update from nodes*/
 | 
			
		||||
#define BBR_REQUIRE_DAO_REFRESH   0x0000 /**< Deprecated DAO Refresh is now the default functionality*/
 | 
			
		||||
#define BBR_PERIODIC_VERSION_INC  0x0010 /**< Increment PAN version number Periodically*/
 | 
			
		||||
#define BBR_GUA_SLAAC             0x0020 /**< in Global prefix use SLAAC address generation to reduce traffic during bootstrap */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file ws_management_if.h
 | 
			
		||||
 * \file ws_management_api.h
 | 
			
		||||
 * \brief Wi-SUN management interface.
 | 
			
		||||
 *
 | 
			
		||||
 * This interface is used for configuring Wi-SUN devices.
 | 
			
		||||
| 
						 | 
				
			
			@ -37,61 +37,63 @@ extern "C" {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
/* Regulatory domain values*/
 | 
			
		||||
#define REG_DOMAIN_WW   0x00 // World wide
 | 
			
		||||
#define REG_DOMAIN_NA   0x01 // North America
 | 
			
		||||
#define REG_DOMAIN_JP   0x02 // Japan
 | 
			
		||||
#define REG_DOMAIN_EU   0x03 // European Union
 | 
			
		||||
#define REG_DOMAIN_CH   0x04 // China
 | 
			
		||||
#define REG_DOMAIN_IN   0x05 // India
 | 
			
		||||
#define REG_DOMAIN_MX   0x06 //
 | 
			
		||||
#define REG_DOMAIN_BZ   0x07 // Brazil
 | 
			
		||||
#define REG_DOMAIN_AZ   0x08 // Australia
 | 
			
		||||
#define REG_DOMAIN_NZ   0x08 // New zealand
 | 
			
		||||
#define REG_DOMAIN_KR   0x09 // Korea
 | 
			
		||||
#define REG_DOMAIN_PH   0x0A //
 | 
			
		||||
#define REG_DOMAIN_MY   0x0B //
 | 
			
		||||
#define REG_DOMAIN_HK   0x0C //
 | 
			
		||||
#define REG_DOMAIN_SG   0x0D // band 866-869
 | 
			
		||||
#define REG_DOMAIN_TH   0x0E //
 | 
			
		||||
#define REG_DOMAIN_VN   0x0F //
 | 
			
		||||
#define REG_DOMAIN_SG_H 0x10 // band 920-925
 | 
			
		||||
#define REG_DOMAIN_WW   0x00 /**< World wide */
 | 
			
		||||
#define REG_DOMAIN_NA   0x01 /**< North America */
 | 
			
		||||
#define REG_DOMAIN_JP   0x02 /**< Japan */
 | 
			
		||||
#define REG_DOMAIN_EU   0x03 /**< European Union */
 | 
			
		||||
#define REG_DOMAIN_CH   0x04 /**< China */
 | 
			
		||||
#define REG_DOMAIN_IN   0x05 /**< India */
 | 
			
		||||
#define REG_DOMAIN_MX   0x06 /**< Mexico */
 | 
			
		||||
#define REG_DOMAIN_BZ   0x07 /**< Brazil */
 | 
			
		||||
#define REG_DOMAIN_AZ   0x08 /**< Australia */
 | 
			
		||||
#define REG_DOMAIN_NZ   0x08 /**< New zealand */
 | 
			
		||||
#define REG_DOMAIN_KR   0x09 /**< Korea */
 | 
			
		||||
#define REG_DOMAIN_PH   0x0A /**< Philippines */
 | 
			
		||||
#define REG_DOMAIN_MY   0x0B /**< Malaysia */
 | 
			
		||||
#define REG_DOMAIN_HK   0x0C /**< Hong Kong */
 | 
			
		||||
#define REG_DOMAIN_SG   0x0D /**< Singapore band 866-869 */
 | 
			
		||||
#define REG_DOMAIN_TH   0x0E /**< Thailand */
 | 
			
		||||
#define REG_DOMAIN_VN   0x0F /**< Vietnam */
 | 
			
		||||
#define REG_DOMAIN_SG_H 0x10 /**< Singapore band 920-925 */
 | 
			
		||||
 | 
			
		||||
#define OPERATING_MODE_1a 0x1a
 | 
			
		||||
#define OPERATING_MODE_1b 0x1b
 | 
			
		||||
#define OPERATING_MODE_2a 0x2a
 | 
			
		||||
#define OPERATING_MODE_2b 0x2b
 | 
			
		||||
#define OPERATING_MODE_3  0x03
 | 
			
		||||
#define OPERATING_MODE_4a 0x4a
 | 
			
		||||
#define OPERATING_MODE_4b 0x4b
 | 
			
		||||
#define OPERATING_MODE_5  0x05
 | 
			
		||||
#define OPERATING_MODE_1a 0x1a  /**< 50, 0,5 */
 | 
			
		||||
#define OPERATING_MODE_1b 0x1b  /**< 50, 1.0 */
 | 
			
		||||
#define OPERATING_MODE_2a 0x2a  /**< 100, 0,5 */
 | 
			
		||||
#define OPERATING_MODE_2b 0x2b  /**< 100, 1.0 */
 | 
			
		||||
#define OPERATING_MODE_3  0x03  /**< 150, 0.5 */
 | 
			
		||||
#define OPERATING_MODE_4a 0x4a  /**< 200, 0.5 */
 | 
			
		||||
#define OPERATING_MODE_4b 0x4b  /**< 200, 1.0 */
 | 
			
		||||
#define OPERATING_MODE_5  0x05  /**< 300, 0.5 */
 | 
			
		||||
 | 
			
		||||
#define CHANNEL_FUNCTION_FIXED            0x00 // Fixed channel
 | 
			
		||||
#define CHANNEL_FUNCTION_TR51CF           0x01 // TR51CF
 | 
			
		||||
#define CHANNEL_FUNCTION_DH1CF            0x02 // Direct Hash
 | 
			
		||||
#define CHANNEL_FUNCTION_VENDOR_DEFINED   0x03 // vendor given channel hop schedule
 | 
			
		||||
#define CHANNEL_FUNCTION_FIXED            0x00  /**< Fixed channel */
 | 
			
		||||
#define CHANNEL_FUNCTION_TR51CF           0x01  /**< TR51CF */
 | 
			
		||||
#define CHANNEL_FUNCTION_DH1CF            0x02  /**< Direct Hash */
 | 
			
		||||
#define CHANNEL_FUNCTION_VENDOR_DEFINED   0x03  /**< vendor given channel hop schedule */
 | 
			
		||||
 | 
			
		||||
#define CHANNEL_SPACING_200 0x00 // 200 khz
 | 
			
		||||
#define CHANNEL_SPACING_400 0x01 // 400 khz
 | 
			
		||||
#define CHANNEL_SPACING_600 0x02 // 600 khz
 | 
			
		||||
#define CHANNEL_SPACING_100 0x03 // 100 khz
 | 
			
		||||
#define CHANNEL_SPACING_250 0x04 // 250 khz
 | 
			
		||||
#define CHANNEL_SPACING_200     0x00    /**< 200 khz */
 | 
			
		||||
#define CHANNEL_SPACING_400     0x01    /**< 400 khz */
 | 
			
		||||
#define CHANNEL_SPACING_600     0x02    /**< 600 khz */
 | 
			
		||||
#define CHANNEL_SPACING_100     0x03    /**< 100 khz */
 | 
			
		||||
#define CHANNEL_SPACING_250     0x04    /**< 250 khz */
 | 
			
		||||
#define CHANNEL_SPACING_800     0x05    /**< 800 khz */
 | 
			
		||||
#define CHANNEL_SPACING_1200    0x06    /**< 1200 khz */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  Network Size definitions are device amount in hundreds of devices.
 | 
			
		||||
 *  These definitions are meant to give some estimates of sizes. Any value can be given as parameter
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define NETWORK_SIZE_CERTIFICATE    0x00  // Network configuration used in Wi-SUN certification
 | 
			
		||||
#define NETWORK_SIZE_SMALL          0x01  // Small networks
 | 
			
		||||
#define NETWORK_SIZE_MEDIUM         0x08  // 100 - 800 device networks are medium sized
 | 
			
		||||
#define NETWORK_SIZE_LARGE          0x0F  // 800 - 1500 device networks are large
 | 
			
		||||
#define NETWORK_SIZE_XLARGE         0x19  // 2500+ devices
 | 
			
		||||
#define NETWORK_SIZE_AUTOMATIC      0xFF
 | 
			
		||||
#define NETWORK_SIZE_CERTIFICATE    0x00    /**< Network configuration used in Wi-SUN certification */
 | 
			
		||||
#define NETWORK_SIZE_SMALL          0x01    /**< Small networks */
 | 
			
		||||
#define NETWORK_SIZE_MEDIUM         0x08    /**< 100 - 800 device networks are medium sized */
 | 
			
		||||
#define NETWORK_SIZE_LARGE          0x0F    /**< 800 - 1500 device networks are large */
 | 
			
		||||
#define NETWORK_SIZE_XLARGE         0x19    /**< 2500+ devices */
 | 
			
		||||
#define NETWORK_SIZE_AUTOMATIC      0xFF    /**< Automatic network size */
 | 
			
		||||
 | 
			
		||||
/** Temporary API change flag. this will be removed when new version of API is implemented on applications
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define WS_MANAGEMENT_API_VER_2
 | 
			
		||||
#define WS_MANAGEMENT_API_VER_2 /**< Management API version */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Struct ws_statistics defines the Wi-SUN statistics storage structure.
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +186,83 @@ int ws_management_network_name_validate(
 | 
			
		|||
    int8_t interface_id,
 | 
			
		||||
    char *network_name_ptr);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configure PHY mode ID of Wi-SUN stack as defined by Wi-SUN FAN 1.1.
 | 
			
		||||
 *
 | 
			
		||||
 * Change the default configuration for Wi-SUN PHY operation.
 | 
			
		||||
 *
 | 
			
		||||
 * Supported values:
 | 
			
		||||
 * FSK without FEC:
 | 
			
		||||
 * PHY mode ID | Symbol Rate (kbps) | Modulation Index
 | 
			
		||||
 *           1                   50                0.5
 | 
			
		||||
 *           2                   50                1.0
 | 
			
		||||
 *           3                  100                0.5
 | 
			
		||||
 *           4                  100                1.0
 | 
			
		||||
 *           5                  150                0.5
 | 
			
		||||
 *           6                  200                0.5
 | 
			
		||||
 *           7                  200                1.0
 | 
			
		||||
 *           8                  300                0.5
 | 
			
		||||
 *
 | 
			
		||||
 * FSK with FEC:
 | 
			
		||||
 * PHY mode ID | Symbol Rate (kbps) | Modulation Index
 | 
			
		||||
 *          17                   50                0.5
 | 
			
		||||
 *          18                   50                1.0
 | 
			
		||||
 *          19                  100                0.5
 | 
			
		||||
 *          20                  100                1.0
 | 
			
		||||
 *          21                  150                0.5
 | 
			
		||||
 *          22                  200                0.5
 | 
			
		||||
 *          23                  200                1.0
 | 
			
		||||
 *          24                  300                0.5
 | 
			
		||||
 *
 | 
			
		||||
 * OFDM:
 | 
			
		||||
 * PHY mode ID | Option | MCS | Data rate (kbps)
 | 
			
		||||
 *          34        1     2                400
 | 
			
		||||
 *          35        1     3                800
 | 
			
		||||
 *          36        1     4               1200
 | 
			
		||||
 *          37        1     5               1600
 | 
			
		||||
 *          38        1     6               2400
 | 
			
		||||
 *          51        2     3                400
 | 
			
		||||
 *          52        2     4                600
 | 
			
		||||
 *          53        2     5                800
 | 
			
		||||
 *          54        2     6               1200
 | 
			
		||||
 *          68        3     4                300
 | 
			
		||||
 *          69        3     5                400
 | 
			
		||||
 *          70        3     6                600
 | 
			
		||||
 *          84        4     4                150
 | 
			
		||||
 *          85        4     5                200
 | 
			
		||||
 *          86        4     6                300
 | 
			
		||||
 *
 | 
			
		||||
 * if value of 255 is given then previous value is used.
 | 
			
		||||
 *
 | 
			
		||||
 * \param interface_id Network interface ID.
 | 
			
		||||
 * \param phy_mode_id PHY mode ID. Default 255 (not used).
 | 
			
		||||
 *
 | 
			
		||||
 * \return 0, Init OK.
 | 
			
		||||
 * \return <0 Init fail.
 | 
			
		||||
 */
 | 
			
		||||
int ws_management_phy_mode_id_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t phy_mode_id);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configure Channel plan ID of Wi-SUN stack as defined by Wi-SUN FAN 1.1.
 | 
			
		||||
 *
 | 
			
		||||
 * Change the default channel configuration for Wi-SUN.
 | 
			
		||||
 *
 | 
			
		||||
 * Supported values: TBD
 | 
			
		||||
 *
 | 
			
		||||
 * if value of 255 is given then previous value is used.
 | 
			
		||||
 *
 | 
			
		||||
 * \param interface_id Network interface ID.
 | 
			
		||||
 * \param channel_plan_id Channel plan ID. Default 255 (not used).
 | 
			
		||||
 *
 | 
			
		||||
 * \return 0, Init OK.
 | 
			
		||||
 * \return <0 Init fail.
 | 
			
		||||
 */
 | 
			
		||||
int ws_management_channel_plan_id_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t channel_plan_id);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configure regulatory domain of Wi-SUN stack.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -799,15 +799,15 @@ bool protocol_6lowpan_latency_estimate_get(int8_t interface_id, uint32_t *latenc
 | 
			
		|||
 | 
			
		||||
    if (cur_interface->eth_mac_api) {
 | 
			
		||||
        // either PPP or Ethernet interface.
 | 
			
		||||
        latency_estimate = 100;
 | 
			
		||||
        latency_estimate = 1000;
 | 
			
		||||
    } else if (thread_info(cur_interface)) {
 | 
			
		||||
        // thread network
 | 
			
		||||
        latency_estimate = 2000;
 | 
			
		||||
        latency_estimate = 5000;
 | 
			
		||||
    } else if (ws_info(cur_interface)) {
 | 
			
		||||
        latency_estimate = ws_common_latency_estimate_get(cur_interface);
 | 
			
		||||
    } else {
 | 
			
		||||
        // 6LoWPAN ND
 | 
			
		||||
        latency_estimate = 8000;
 | 
			
		||||
        latency_estimate = 20000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (latency_estimate != 0) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -930,7 +930,7 @@ bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uin
 | 
			
		|||
    /* TODO - check hard upper limit on registrations? */
 | 
			
		||||
    if (ws_info(cur_interface)) {
 | 
			
		||||
 | 
			
		||||
        aro_out->status = ws_common_allow_child_registration(cur_interface, aro_out->eui64);
 | 
			
		||||
        aro_out->status = ws_common_allow_child_registration(cur_interface, aro_out->eui64, aro_out->lifetime);
 | 
			
		||||
        if (aro_out->status != ARO_SUCCESS) {
 | 
			
		||||
            aro_out->present = true;
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,13 +42,14 @@
 | 
			
		|||
#include "MLE/mle.h"
 | 
			
		||||
#include "Service_Libs/mle_service/mle_service_api.h"
 | 
			
		||||
#include "Common_Protocols/icmpv6.h"
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
#ifdef HAVE_RPL
 | 
			
		||||
#include "RPL/rpl_data.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
 | 
			
		||||
#include "6LoWPAN/Thread/thread_common.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_common.h"
 | 
			
		||||
 | 
			
		||||
#include "Service_Libs/random_early_detection/random_early_detection_api.h"
 | 
			
		||||
#define TRACE_GROUP "6lAd"
 | 
			
		||||
 | 
			
		||||
typedef void (adaptation_etx_update_cb)(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm);
 | 
			
		||||
| 
						 | 
				
			
			@ -60,6 +61,8 @@ typedef void (adaptation_etx_update_cb)(protocol_interface_info_entry_t *cur, bu
 | 
			
		|||
#define tr_debug_extra(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ADAPTION_DIRECT_TX_QUEUE_SIZE_THRESHOLD_TRACE 20
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint16_t tag;   /*!< Fragmentation datagram TAG ID */
 | 
			
		||||
    uint16_t size;  /*!< Datagram Total Size (uncompressed) */
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +96,8 @@ typedef struct {
 | 
			
		|||
    fragmenter_tx_list_t activeUnicastList; //Unicast packets waiting data confirmation from MAC
 | 
			
		||||
    buffer_list_t directTxQueue; //Waiting free tx process
 | 
			
		||||
    uint16_t directTxQueue_size;
 | 
			
		||||
    uint16_t directTxQueue_level;
 | 
			
		||||
    uint16_t activeTxList_size;
 | 
			
		||||
    uint16_t indirect_big_packet_threshold;
 | 
			
		||||
    uint16_t max_indirect_big_packets_total;
 | 
			
		||||
    uint16_t max_indirect_small_packets_per_child;
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +108,17 @@ typedef struct {
 | 
			
		|||
    ns_list_link_t      link; /*!< List link entry */
 | 
			
		||||
} fragmenter_interface_t;
 | 
			
		||||
 | 
			
		||||
#define LOWPAN_ACTIVE_UNICAST_ONGOING_MAX 10
 | 
			
		||||
 | 
			
		||||
/* Minimum buffer amount and memory size to ensure operation even in out of memory situation
 | 
			
		||||
 */
 | 
			
		||||
#define LOWPAN_MEM_LIMIT_MIN_QUEUE 10
 | 
			
		||||
#define LOWPAN_MEM_LIMIT_MIN_MEMORY 10000
 | 
			
		||||
#define LOWPAN_MEM_LIMIT_REMOVE_NORMAL 3000 // Remove when approaching memory limit
 | 
			
		||||
#define LOWPAN_MEM_LIMIT_REMOVE_MAX 10000 // Remove when at memory limit
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static NS_LIST_DEFINE(fragmenter_interface_list, fragmenter_interface_t, link);
 | 
			
		||||
 | 
			
		||||
/* Adaptation interface local functions */
 | 
			
		||||
| 
						 | 
				
			
			@ -203,11 +219,22 @@ static struct protocol_interface_info_entry *lowpan_adaptation_network_interface
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void lowpan_adaptation_tx_queue_level_update(fragmenter_interface_t *interface_ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (interface_ptr->directTxQueue_size == interface_ptr->directTxQueue_level + ADAPTION_DIRECT_TX_QUEUE_SIZE_THRESHOLD_TRACE ||
 | 
			
		||||
            interface_ptr->directTxQueue_size == interface_ptr->directTxQueue_level - ADAPTION_DIRECT_TX_QUEUE_SIZE_THRESHOLD_TRACE) {
 | 
			
		||||
        interface_ptr->directTxQueue_level = interface_ptr->directTxQueue_size;
 | 
			
		||||
        tr_info("Adaptation layer TX queue size %u Active MAC tx request %u", interface_ptr->directTxQueue_level, interface_ptr->activeTxList_size);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr, buffer_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    buffer_t *lower_priority_buf = NULL;
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach(buffer_t, cur, &interface_ptr->directTxQueue) {
 | 
			
		||||
 | 
			
		||||
        if (cur->priority < buf->priority) {
 | 
			
		||||
            lower_priority_buf = cur;
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -220,6 +247,7 @@ static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_p
 | 
			
		|||
        ns_list_add_to_end(&interface_ptr->directTxQueue, buf);
 | 
			
		||||
    }
 | 
			
		||||
    interface_ptr->directTxQueue_size++;
 | 
			
		||||
    lowpan_adaptation_tx_queue_level_update(interface_ptr);
 | 
			
		||||
    protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -233,6 +261,7 @@ static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interfa
 | 
			
		|||
        if (lowpan_buffer_tx_allowed(interface_ptr, buf)) {
 | 
			
		||||
            ns_list_remove(&interface_ptr->directTxQueue, buf);
 | 
			
		||||
            interface_ptr->directTxQueue_size--;
 | 
			
		||||
            lowpan_adaptation_tx_queue_level_update(interface_ptr);
 | 
			
		||||
            protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
 | 
			
		||||
            return buf;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -365,6 +394,9 @@ int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_si
 | 
			
		|||
    ns_list_init(&interface_ptr->indirect_tx_queue);
 | 
			
		||||
    ns_list_init(&interface_ptr->directTxQueue);
 | 
			
		||||
    ns_list_init(&interface_ptr->activeUnicastList);
 | 
			
		||||
    interface_ptr->activeTxList_size = 0;
 | 
			
		||||
    interface_ptr->directTxQueue_size = 0;
 | 
			
		||||
    interface_ptr->directTxQueue_level = 0;
 | 
			
		||||
 | 
			
		||||
    ns_list_add_to_end(&fragmenter_interface_list, interface_ptr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -390,13 +422,15 @@ int8_t lowpan_adaptation_interface_free(int8_t interface_id)
 | 
			
		|||
    ns_list_remove(&fragmenter_interface_list, interface_ptr);
 | 
			
		||||
    //free active tx process
 | 
			
		||||
    lowpan_list_free(&interface_ptr->activeUnicastList, false);
 | 
			
		||||
    interface_ptr->activeTxList_size = 0;
 | 
			
		||||
    lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
 | 
			
		||||
 | 
			
		||||
    //Free Indirect entry
 | 
			
		||||
    lowpan_list_free(&interface_ptr->indirect_tx_queue, true);
 | 
			
		||||
 | 
			
		||||
    buffer_free_list(&interface_ptr->directTxQueue);
 | 
			
		||||
 | 
			
		||||
    interface_ptr->directTxQueue_size = 0;
 | 
			
		||||
    interface_ptr->directTxQueue_level = 0;
 | 
			
		||||
    //Free Dynamic allocated entries
 | 
			
		||||
    ns_dyn_mem_free(interface_ptr->fragment_indirect_tx_buffer);
 | 
			
		||||
    ns_dyn_mem_free(interface_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -415,6 +449,7 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id)
 | 
			
		|||
 | 
			
		||||
    //free active tx process
 | 
			
		||||
    lowpan_list_free(&interface_ptr->activeUnicastList, false);
 | 
			
		||||
    interface_ptr->activeTxList_size  = 0;
 | 
			
		||||
    lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
 | 
			
		||||
    //Clean fragmented message flag
 | 
			
		||||
    interface_ptr->fragmenter_active = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -423,6 +458,8 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id)
 | 
			
		|||
    lowpan_list_free(&interface_ptr->indirect_tx_queue, true);
 | 
			
		||||
 | 
			
		||||
    buffer_free_list(&interface_ptr->directTxQueue);
 | 
			
		||||
    interface_ptr->directTxQueue_size = 0;
 | 
			
		||||
    interface_ptr->directTxQueue_level = 0;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -465,6 +502,63 @@ int8_t lowpan_adaptation_interface_mpx_register(int8_t interface_id, struct mpx_
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lowpan_adaptation_free_heap(bool full_gc)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach(fragmenter_interface_t, interface_ptr, &fragmenter_interface_list) {
 | 
			
		||||
        // Go through all interfaces and free small amount of memory
 | 
			
		||||
        // This is not very radical, but gives time to recover wthout causing too harsh changes
 | 
			
		||||
        lowpan_adaptation_free_low_priority_packets(interface_ptr->interface_id, full_gc ? LOWPAN_MEM_LIMIT_REMOVE_MAX : LOWPAN_MEM_LIMIT_REMOVE_NORMAL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, uint32_t requested_amount)
 | 
			
		||||
{
 | 
			
		||||
    fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
 | 
			
		||||
 | 
			
		||||
    if (!interface_ptr) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t adaptation_memory = 0;
 | 
			
		||||
    uint16_t adaptation_packets = 0;
 | 
			
		||||
    uint32_t memory_freed = 0;
 | 
			
		||||
    uint16_t packets_freed = 0;
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach(buffer_t, entry, &interface_ptr->directTxQueue) {
 | 
			
		||||
        adaptation_memory += sizeof(buffer_t) + entry->size;
 | 
			
		||||
        adaptation_packets++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (interface_ptr->directTxQueue_size < LOWPAN_MEM_LIMIT_MIN_QUEUE) {
 | 
			
		||||
        // Minimum reserved for operations
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (adaptation_memory < LOWPAN_MEM_LIMIT_MIN_MEMORY) {
 | 
			
		||||
        // Minimum reserved for operations
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (adaptation_memory - requested_amount < LOWPAN_MEM_LIMIT_MIN_MEMORY) {
 | 
			
		||||
        // only reduse to minimum
 | 
			
		||||
        requested_amount = adaptation_memory - LOWPAN_MEM_LIMIT_MIN_MEMORY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Only remove last entries from TX queue with low priority
 | 
			
		||||
    ns_list_foreach_reverse_safe(buffer_t, entry, &interface_ptr->directTxQueue) {
 | 
			
		||||
        if (entry->priority == QOS_NORMAL) {
 | 
			
		||||
            memory_freed += sizeof(buffer_t) + entry->size;
 | 
			
		||||
            packets_freed++;
 | 
			
		||||
            ns_list_remove(&interface_ptr->directTxQueue, entry);
 | 
			
		||||
            interface_ptr->directTxQueue_size--;
 | 
			
		||||
            lowpan_adaptation_tx_queue_level_update(interface_ptr);
 | 
			
		||||
            socket_tx_buffer_event_and_free(entry, SOCKET_TX_FAIL);
 | 
			
		||||
        }
 | 
			
		||||
        if (memory_freed > requested_amount) {
 | 
			
		||||
            // Enough memory freed
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    tr_info("Adaptation Free low priority packets memory: %" PRIi32 " queue: %d deallocated %" PRIi32 " bytes, %d packets, %" PRIi32 " requested", adaptation_memory, adaptation_packets, memory_freed, packets_freed, requested_amount);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_indirect_entry_allocate(uint16_t fragment_buffer_size)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -597,6 +691,7 @@ static fragmenter_tx_entry_t *lowpan_adaptation_tx_process_init(fragmenter_inter
 | 
			
		|||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
            ns_list_add_to_end(&interface_ptr->activeUnicastList, tx_entry);
 | 
			
		||||
            interface_ptr->activeTxList_size++;
 | 
			
		||||
        } else {
 | 
			
		||||
            tx_entry = &interface_ptr->active_broadcast_tx_buf;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -969,6 +1064,13 @@ static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buff
 | 
			
		|||
    if (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (is_unicast && interface_ptr->activeTxList_size >= LOWPAN_ACTIVE_UNICAST_ONGOING_MAX) {
 | 
			
		||||
        //New TX is not possible there is already too manyactive connecting
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Do not accept more than one active unicast TX per destination
 | 
			
		||||
    if (is_unicast && lowpan_adaptation_is_destination_tx_active(&interface_ptr->activeUnicastList, buf)) {
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -992,6 +1094,18 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
 | 
			
		|||
        goto tx_error_handler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t traffic_class = buf->options.traffic_class >> IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
 | 
			
		||||
    if (traffic_class == IP_DSCP_EF) {
 | 
			
		||||
        buffer_priority_set(buf, QOS_EXPEDITE_FORWARD);
 | 
			
		||||
    } else if (traffic_class == IP_DSCP_CS6) {
 | 
			
		||||
        //Network Control
 | 
			
		||||
        buffer_priority_set(buf, QOS_NETWORK_CTRL);
 | 
			
		||||
    } else if (traffic_class) {
 | 
			
		||||
        buffer_priority_set(buf, QOS_HIGH);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //Check packet size
 | 
			
		||||
    bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
 | 
			
		||||
    if (fragmented_needed) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1010,7 +1124,18 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
 | 
			
		|||
    bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess;
 | 
			
		||||
 | 
			
		||||
    if (!lowpan_buffer_tx_allowed(interface_ptr, buf)) {
 | 
			
		||||
 | 
			
		||||
        if (buf->priority == QOS_NORMAL) {
 | 
			
		||||
 | 
			
		||||
            if (random_early_detection_congestion_check(cur->random_early_detection)) {
 | 
			
		||||
                random_early_detetction_aq_calc(cur->random_early_detection, interface_ptr->directTxQueue_size);
 | 
			
		||||
                protocol_stats_update(STATS_AL_TX_CONGESTION_DROP, 1);
 | 
			
		||||
                goto tx_error_handler;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        lowpan_adaptation_tx_queue_write(interface_ptr, buf);
 | 
			
		||||
        random_early_detetction_aq_calc(cur->random_early_detection, interface_ptr->directTxQueue_size);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1166,6 +1291,7 @@ static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interfa
 | 
			
		|||
    } else if (buf->link_specific.ieee802_15_4.requestAck) {
 | 
			
		||||
        ns_list_remove(&interface_ptr->activeUnicastList, tx_ptr);
 | 
			
		||||
        ns_dyn_mem_free(tx_ptr);
 | 
			
		||||
        interface_ptr->activeTxList_size--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    socket_tx_buffer_event_and_free(buf, socket_event);
 | 
			
		||||
| 
						 | 
				
			
			@ -1205,7 +1331,6 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
 | 
			
		|||
        tr_error("No data request for this confirmation %u", confirm->msduHandle);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Check status for
 | 
			
		||||
    buffer_t *buf = tx_ptr->buf;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1229,64 +1354,58 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
 | 
			
		|||
        buf->link_specific.ieee802_15_4.rf_channel_switch = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (confirm->status) {
 | 
			
		||||
 | 
			
		||||
        case MLME_BUSY_CHAN:
 | 
			
		||||
            lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
 | 
			
		||||
            break;
 | 
			
		||||
        case MLME_SUCCESS:
 | 
			
		||||
 | 
			
		||||
            //Check is there more packets
 | 
			
		||||
            if (lowpan_adaptation_tx_process_ready(tx_ptr)) {
 | 
			
		||||
                bool triggered_from_indirect_cache = false;
 | 
			
		||||
                if (tx_ptr->fragmented_data && active_direct_confirm) {
 | 
			
		||||
                    //Clean
 | 
			
		||||
                    interface_ptr->fragmenter_active = false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (tx_ptr->buf->link_specific.ieee802_15_4.indirectTxProcess) {
 | 
			
		||||
                    triggered_from_indirect_cache = lowpan_adaptation_indirect_cache_trigger(cur, interface_ptr, tx_ptr);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
 | 
			
		||||
 | 
			
		||||
                if (triggered_from_indirect_cache) {
 | 
			
		||||
                    return 0;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
 | 
			
		||||
    if (confirm->status == MLME_SUCCESS) {
 | 
			
		||||
        //Check is there more packets
 | 
			
		||||
        if (lowpan_adaptation_tx_process_ready(tx_ptr)) {
 | 
			
		||||
            bool triggered_from_indirect_cache = false;
 | 
			
		||||
            if (tx_ptr->fragmented_data && active_direct_confirm) {
 | 
			
		||||
                interface_ptr->fragmenter_active = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
        case MLME_TX_NO_ACK:
 | 
			
		||||
        case MLME_SECURITY_FAIL:
 | 
			
		||||
        case MLME_TRANSACTION_EXPIRED:
 | 
			
		||||
        default:
 | 
			
		||||
            tr_error("MCPS Data fail by status %u", confirm->status);
 | 
			
		||||
            if (buf->dst_sa.addr_type == ADDR_802_15_4_SHORT) {
 | 
			
		||||
                tr_info("Dest addr: %x", common_read_16_bit(buf->dst_sa.address + 2));
 | 
			
		||||
            } else if (buf->dst_sa.addr_type == ADDR_802_15_4_LONG) {
 | 
			
		||||
                tr_info("Dest addr: %s", trace_array(buf->dst_sa.address + 2, 8));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RPL
 | 
			
		||||
            if (confirm->status == MLME_TX_NO_ACK || confirm->status == MLME_UNAVAILABLE_KEY) {
 | 
			
		||||
                if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) {
 | 
			
		||||
                    protocol_stats_update(STATS_RPL_PARENT_TX_FAIL, 1);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
            if (tx_ptr->fragmented_data) {
 | 
			
		||||
                tx_ptr->buf->buf_ptr = tx_ptr->buf->buf_end;
 | 
			
		||||
                tx_ptr->buf->buf_ptr -= tx_ptr->orig_size;
 | 
			
		||||
                if (active_direct_confirm) {
 | 
			
		||||
                    interface_ptr->fragmenter_active = false;
 | 
			
		||||
                }
 | 
			
		||||
            if (tx_ptr->buf->link_specific.ieee802_15_4.indirectTxProcess) {
 | 
			
		||||
                triggered_from_indirect_cache = lowpan_adaptation_indirect_cache_trigger(cur, interface_ptr, tx_ptr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
            if (triggered_from_indirect_cache) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
 | 
			
		||||
        }
 | 
			
		||||
    } else if ((confirm->status == MLME_BUSY_CHAN) && !ws_info(cur)) {
 | 
			
		||||
        lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (confirm->status == MLME_TRANSACTION_OVERFLOW) {
 | 
			
		||||
            tr_error("MCPS Data fail by MLME_TRANSACTION_OVERFLOW");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tr_error("MCPS Data fail by status %u", confirm->status);
 | 
			
		||||
        if (buf->dst_sa.addr_type == ADDR_802_15_4_SHORT) {
 | 
			
		||||
            tr_info("Dest addr: %x", common_read_16_bit(buf->dst_sa.address + 2));
 | 
			
		||||
        } else if (buf->dst_sa.addr_type == ADDR_802_15_4_LONG) {
 | 
			
		||||
            tr_info("Dest addr: %s", trace_array(buf->dst_sa.address + 2, 8));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RPL
 | 
			
		||||
        if (confirm->status == MLME_TX_NO_ACK || confirm->status == MLME_UNAVAILABLE_KEY) {
 | 
			
		||||
            if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) {
 | 
			
		||||
                protocol_stats_update(STATS_RPL_PARENT_TX_FAIL, 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        if (tx_ptr->fragmented_data) {
 | 
			
		||||
            tx_ptr->buf->buf_ptr = tx_ptr->buf->buf_end;
 | 
			
		||||
            tx_ptr->buf->buf_ptr -= tx_ptr->orig_size;
 | 
			
		||||
            if (active_direct_confirm) {
 | 
			
		||||
                interface_ptr->fragmenter_active = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
 | 
			
		||||
    }
 | 
			
		||||
    // When confirmation is for direct transmission, push all allowed buffers to MAC
 | 
			
		||||
    if (active_direct_confirm == true) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1295,6 +1414,8 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
 | 
			
		|||
            lowpan_adaptation_interface_tx(cur, buf_from_queue);
 | 
			
		||||
            buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr);
 | 
			
		||||
        }
 | 
			
		||||
        //Update Average QUEUE
 | 
			
		||||
        random_early_detetction_aq_calc(cur->random_early_detection, interface_ptr->directTxQueue_size);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1492,10 +1613,21 @@ int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_in
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Check next directTxQueue there may be pending packets also
 | 
			
		||||
    ns_list_foreach_safe(buffer_t, entry, &interface_ptr->directTxQueue) {
 | 
			
		||||
        if (lowpan_tx_buffer_address_compare(&entry->dst_sa, address_ptr, adr_type)) {
 | 
			
		||||
            ns_list_remove(&interface_ptr->directTxQueue, entry);
 | 
			
		||||
            interface_ptr->directTxQueue_size--;
 | 
			
		||||
            //Update Average QUEUE
 | 
			
		||||
            random_early_detetction_aq_calc(cur->random_early_detection, interface_ptr->directTxQueue_size);
 | 
			
		||||
            lowpan_adaptation_tx_queue_level_update(interface_ptr);
 | 
			
		||||
            socket_tx_buffer_event_and_free(entry, SOCKET_TX_FAIL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int8_t lowpan_adaptation_indirect_queue_params_set(struct protocol_interface_info_entry *cur, uint16_t indirect_big_packet_threshold, uint16_t max_indirect_big_packets_total, uint16_t max_indirect_small_packets_per_child)
 | 
			
		||||
{
 | 
			
		||||
    fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,8 +36,13 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id);
 | 
			
		|||
 | 
			
		||||
int8_t lowpan_adaptation_interface_mpx_register(int8_t interface_id, struct mpx_api_s *mpx_api, uint16_t mpx_user_id);
 | 
			
		||||
 | 
			
		||||
void lowpan_adaptation_free_heap(bool full_gc);
 | 
			
		||||
 | 
			
		||||
int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, uint32_t requested_amount);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief call this before normatl TX. This function prepare buffer link spesific metadata and verify packet destination
 | 
			
		||||
 * \brief call this before normal TX. This function prepare buffer link specific metadata and verify packet destination
 | 
			
		||||
 */
 | 
			
		||||
struct buffer *lowpan_adaptation_data_process_tx_preprocess(struct protocol_interface_info_entry *cur, struct buffer *buf);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -176,12 +176,12 @@ static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur,
 | 
			
		|||
        //stable version for RPL so slow timer update is ok
 | 
			
		||||
        cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_SMALL) {
 | 
			
		||||
            // handles also NETWORK_SIZE_CERTIFICATE
 | 
			
		||||
        if (ws_cfg_network_config_get(cur) <= CONFIG_SMALL) {
 | 
			
		||||
            // Also handles CONFIG_CERTIFICATE
 | 
			
		||||
            cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_SMALL;
 | 
			
		||||
        } else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM) {
 | 
			
		||||
        } else if (ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM) {
 | 
			
		||||
            cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_MEDIUM;
 | 
			
		||||
        } else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_LARGE) {
 | 
			
		||||
        } else if (ws_cfg_network_config_get(cur) <= CONFIG_LARGE) {
 | 
			
		||||
            cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_LARGE;
 | 
			
		||||
        } else  {
 | 
			
		||||
            cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE;
 | 
			
		||||
| 
						 | 
				
			
			@ -712,11 +712,13 @@ void ws_bbr_pan_version_increase(protocol_interface_info_entry_t *cur)
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    tr_debug("Border router version number update");
 | 
			
		||||
    if (configuration & BBR_REQUIRE_DAO_REFRESH) {
 | 
			
		||||
    if (configuration & BBR_PERIODIC_VERSION_INC) {
 | 
			
		||||
        // Periodically increase the version number.
 | 
			
		||||
        // This removes need for DAO, but causes slowness in recovery
 | 
			
		||||
        pan_version_timer = cur->ws_info->cfg->timing.pan_timeout / PAN_VERSION_CHANGE_INTERVAL;
 | 
			
		||||
    } else {
 | 
			
		||||
        // Version number is not periodically increased forcing nodes to check Border router availability using DAO
 | 
			
		||||
        pan_version_timer = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        pan_version_timer = cur->ws_info->cfg->timing.pan_timeout / PAN_VERSION_CHANGE_INTERVAL;
 | 
			
		||||
    }
 | 
			
		||||
    cur->ws_info->pan_information.pan_version++;
 | 
			
		||||
    // Inconsistent for border router to make information distribute faster
 | 
			
		||||
| 
						 | 
				
			
			@ -923,12 +925,16 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options)
 | 
			
		|||
 | 
			
		||||
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
 | 
			
		||||
 | 
			
		||||
    if (protocol_6lowpan_rpl_root_dodag &&
 | 
			
		||||
            options != configuration) {
 | 
			
		||||
        //Configuration changed delete previous setup
 | 
			
		||||
        ws_bbr_routing_stop(cur);
 | 
			
		||||
    if (options == configuration) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    //Configuration changed
 | 
			
		||||
    configuration = options;
 | 
			
		||||
    if (protocol_6lowpan_rpl_root_dodag) {
 | 
			
		||||
        // Already active needs to restart
 | 
			
		||||
        ws_bbr_routing_stop(cur);
 | 
			
		||||
        ws_bbr_pan_version_increase(cur);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
#else
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#ifdef HAVE_WS
 | 
			
		||||
#include "ns_types.h"
 | 
			
		||||
#include "ns_trace.h"
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
#include "net_interface.h"
 | 
			
		||||
#include "eventOS_event.h"
 | 
			
		||||
#include "randLIB.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +44,7 @@
 | 
			
		|||
#include "Common_Protocols/icmpv6.h"
 | 
			
		||||
#include "Common_Protocols/icmpv6_radv.h"
 | 
			
		||||
#include "Common_Protocols/ipv6_constants.h"
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
#include "Service_Libs/Trickle/trickle.h"
 | 
			
		||||
#include "Service_Libs/fhss/channel_list.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_common_defines.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +77,7 @@
 | 
			
		|||
#include "6LoWPAN/ws/ws_eapol_auth_relay.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_eapol_relay.h"
 | 
			
		||||
#include "libNET/src/net_dns_internal.h"
 | 
			
		||||
#include "Service_Libs/random_early_detection/random_early_detection_api.h"
 | 
			
		||||
 | 
			
		||||
#define TRACE_GROUP "wsbs"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -111,6 +114,10 @@ static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, pa
 | 
			
		|||
static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur);
 | 
			
		||||
static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create);
 | 
			
		||||
static void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry);
 | 
			
		||||
static void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t *cur);
 | 
			
		||||
 | 
			
		||||
static void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur);
 | 
			
		||||
static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    WS_PARENT_SOFT_SYNCH = 0,  /**< let FHSS make decision if synchronization is needed*/
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +170,7 @@ void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_ent
 | 
			
		|||
{
 | 
			
		||||
    mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT);
 | 
			
		||||
 | 
			
		||||
    if (neighbor && neighbor->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) {
 | 
			
		||||
    if (neighbor && neighbor->link_lifetime <= valid_time) {
 | 
			
		||||
        //mlme_device_descriptor_t device_desc;
 | 
			
		||||
        neighbor->lifetime = valid_time;
 | 
			
		||||
        neighbor->link_lifetime = valid_time;
 | 
			
		||||
| 
						 | 
				
			
			@ -426,19 +433,47 @@ static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighb
 | 
			
		|||
        ws_nud_state_clean(cur, nud_entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
if_address_entry_t *ws_probe_aro_address(protocol_interface_info_entry_t *interface)
 | 
			
		||||
{
 | 
			
		||||
    if (interface->global_address_available) {
 | 
			
		||||
        ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) {
 | 
			
		||||
            if (addr_ipv6_scope(address->address, interface) > IPV6_SCOPE_LINK_LOCAL) {
 | 
			
		||||
                return address;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor, bool nud_process)
 | 
			
		||||
{
 | 
			
		||||
    //Send NS
 | 
			
		||||
    uint8_t ll_target[16];
 | 
			
		||||
    aro_t aro_temp;
 | 
			
		||||
    //SET ARO and src address pointer to NULL by default
 | 
			
		||||
    aro_t *aro_ptr = NULL;
 | 
			
		||||
    uint8_t *src_address_ptr = NULL;
 | 
			
		||||
 | 
			
		||||
    ws_bootsrap_create_ll_address(ll_target, neighbor->mac64);
 | 
			
		||||
    if (nud_process) {
 | 
			
		||||
        tr_info("NUD generate NS %u", neighbor->index);
 | 
			
		||||
    } else {
 | 
			
		||||
        tr_info("Probe generate NS %u", neighbor->index);
 | 
			
		||||
        if_address_entry_t *gp_address = ws_probe_aro_address(cur);
 | 
			
		||||
        if (gp_address) {
 | 
			
		||||
            src_address_ptr = gp_address->address;
 | 
			
		||||
            aro_temp.status = ARO_SUCCESS;
 | 
			
		||||
            aro_temp.present = true;
 | 
			
		||||
            memcpy(aro_temp.eui64, cur->mac, 8);
 | 
			
		||||
            //Just Short Test
 | 
			
		||||
            aro_temp.lifetime = 1;
 | 
			
		||||
            aro_ptr = &aro_temp;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL);
 | 
			
		||||
    buffer_t *buffer = icmpv6_build_ns(cur, ll_target, src_address_ptr, true, false, aro_ptr);
 | 
			
		||||
    if (buffer) {
 | 
			
		||||
        buffer->options.traffic_class = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
        protocol_push(buffer);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -592,8 +627,9 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded
 | 
			
		|||
 | 
			
		||||
static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration)
 | 
			
		||||
{
 | 
			
		||||
    ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class);
 | 
			
		||||
    ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class);
 | 
			
		||||
    fhss_configuration->channel_mask_size = cur->ws_info->hopping_schdule.number_of_channels;
 | 
			
		||||
    ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id);
 | 
			
		||||
    ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id);
 | 
			
		||||
    // using bitwise AND operation for user set channel mask to remove channels not allowed in this device
 | 
			
		||||
    for (uint8_t n = 0; n < 8; n++) {
 | 
			
		||||
        fhss_configuration->unicast_channel_mask[n] &= cur->ws_info->cfg->fhss.fhss_channel_mask[n];
 | 
			
		||||
| 
						 | 
				
			
			@ -1518,10 +1554,10 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter
 | 
			
		|||
     */
 | 
			
		||||
    trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit);
 | 
			
		||||
    /*
 | 
			
		||||
     *  Optimized PAN discovery to select faster the parent if we hear solicit from someone else
 | 
			
		||||
     *  Optimized PAN discovery to select the parent faster if we hear solicit from someone else
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    if (ws_bootstrap_state_discovery(cur)  && cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM &&
 | 
			
		||||
    if (ws_bootstrap_state_discovery(cur)  && ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM &&
 | 
			
		||||
            cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) {
 | 
			
		||||
 | 
			
		||||
        cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin);
 | 
			
		||||
| 
						 | 
				
			
			@ -1595,10 +1631,15 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
 | 
			
		|||
 | 
			
		||||
        //When Config is learned and USE Parent BS is enabled compare is this new BSI
 | 
			
		||||
        if (cur->ws_info->configuration_learned && cur->ws_info->pan_information.use_parent_bs && ws_bs_ie.broadcast_schedule_identifier != cur->ws_info->hopping_schdule.fhss_bsi) {
 | 
			
		||||
            tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier);
 | 
			
		||||
            cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout;
 | 
			
		||||
            cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi;
 | 
			
		||||
            ws_bootstrap_event_discovery_start(cur);
 | 
			
		||||
            //Accept only next possible BSI number
 | 
			
		||||
            if ((cur->ws_info->hopping_schdule.fhss_bsi + 1) != ws_bs_ie.broadcast_schedule_identifier) {
 | 
			
		||||
                tr_debug("Do not accept a unknown BSI: %u", ws_bs_ie.broadcast_schedule_identifier);
 | 
			
		||||
            } else {
 | 
			
		||||
                tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier);
 | 
			
		||||
                cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout;
 | 
			
		||||
                cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi;
 | 
			
		||||
                ws_bootstrap_event_discovery_start(cur);
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2007,7 +2048,7 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt
 | 
			
		|||
 | 
			
		||||
static uint32_t ws_probe_init_time_get(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_SMALL) {
 | 
			
		||||
    if (ws_cfg_network_config_get(cur) <= CONFIG_SMALL) {
 | 
			
		||||
        return WS_SMALL_PROBE_INIT_BASE_SECONDS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2359,11 +2400,30 @@ int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t
 | 
			
		|||
static int ws_bootstrap_set_domain_rf_config(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    phy_rf_channel_configuration_s rf_configs;
 | 
			
		||||
    memset(&rf_configs, 0, sizeof(phy_rf_channel_configuration_s));
 | 
			
		||||
 | 
			
		||||
    uint8_t phy_mode_id = cur->ws_info->hopping_schdule.phy_mode_id;
 | 
			
		||||
    if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) ||
 | 
			
		||||
            ((phy_mode_id >= 51) && (phy_mode_id <= 54)) ||
 | 
			
		||||
            ((phy_mode_id >= 68) && (phy_mode_id <= 70)) ||
 | 
			
		||||
            ((phy_mode_id >= 84) && (phy_mode_id <= 86))) {
 | 
			
		||||
        rf_configs.modulation = M_OFDM;
 | 
			
		||||
        rf_configs.datarate = ws_get_datarate_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id);
 | 
			
		||||
        rf_configs.ofdm_option = ws_get_ofdm_option_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id);
 | 
			
		||||
        rf_configs.ofdm_mcs = ws_get_ofdm_mcs_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id);
 | 
			
		||||
    } else {
 | 
			
		||||
        if ((phy_mode_id >= 17) && (phy_mode_id <= 24)) {
 | 
			
		||||
            rf_configs.fec = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            rf_configs.fec = false;
 | 
			
		||||
        }
 | 
			
		||||
        rf_configs.modulation = M_2FSK;
 | 
			
		||||
        rf_configs.datarate = ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode);
 | 
			
		||||
        rf_configs.modulation_index = ws_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rf_configs.channel_0_center_frequency = (uint32_t)cur->ws_info->hopping_schdule.ch0_freq * 100000;
 | 
			
		||||
    rf_configs.channel_spacing = ws_decode_channel_spacing(cur->ws_info->hopping_schdule.channel_spacing);
 | 
			
		||||
    rf_configs.datarate = ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode);
 | 
			
		||||
    rf_configs.modulation_index = ws_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode);
 | 
			
		||||
    rf_configs.modulation = M_2FSK;
 | 
			
		||||
    rf_configs.number_of_channels = cur->ws_info->hopping_schdule.number_of_channels;
 | 
			
		||||
    ws_bootstrap_set_rf_config(cur, rf_configs);
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2522,6 +2582,12 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle)
 | 
			
		|||
            // After successful DAO ACK connection to border router is verified
 | 
			
		||||
            cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!cur->ws_info->trickle_pa_running || !cur->ws_info->trickle_pc_running) {
 | 
			
		||||
            //Enable wi-sun asynch adverisment
 | 
			
		||||
            ws_bootstrap_advertise_start(cur);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ws_set_fhss_hop(cur);
 | 
			
		||||
| 
						 | 
				
			
			@ -2536,6 +2602,12 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle)
 | 
			
		|||
         *
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
    } else if (event == RPL_EVENT_LOCAL_REPAIR_START) {
 | 
			
		||||
        tr_debug("RPL local repair start");
 | 
			
		||||
        //Disable Asynchs
 | 
			
		||||
        ws_bootstrap_asynch_trickle_stop(cur);
 | 
			
		||||
        ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN);
 | 
			
		||||
 | 
			
		||||
    } else if (event == RPL_EVENT_DAO_PARENT_ADD) {
 | 
			
		||||
        ws_address_parent_update(cur);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -3024,9 +3096,9 @@ static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    tr_debug("Start RPL learn");
 | 
			
		||||
    // routers wait until RPL root is contacted
 | 
			
		||||
    ws_bootstrap_state_change(cur, ER_RPL_SCAN);
 | 
			
		||||
    //For Large network and medium shuold do passive scan
 | 
			
		||||
    if (cur->ws_info->cfg->gen.network_size > NETWORK_SIZE_SMALL) {
 | 
			
		||||
        // Set timeout for check to 30 -60 seconds
 | 
			
		||||
    //For Large network and medium should do passive scan
 | 
			
		||||
    if (ws_cfg_network_config_get(cur) > CONFIG_SMALL) {
 | 
			
		||||
        // Set timeout for check to 30 - 60 seconds
 | 
			
		||||
        cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT);
 | 
			
		||||
    }
 | 
			
		||||
    /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border
 | 
			
		||||
| 
						 | 
				
			
			@ -3073,7 +3145,7 @@ static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asy
 | 
			
		|||
        uint16_t channel_number = cur->ws_info->cfg->fhss.fhss_uc_fixed_channel;
 | 
			
		||||
        async_req->channel_list.channel_mask[0 + (channel_number / 32)] = (1 << (channel_number % 32));
 | 
			
		||||
    } else {
 | 
			
		||||
        ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class);
 | 
			
		||||
        ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async_req->channel_list.channel_page = CHANNEL_PAGE_10;
 | 
			
		||||
| 
						 | 
				
			
			@ -3272,6 +3344,8 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
 | 
			
		|||
 | 
			
		||||
            // All trickle timers stopped to allow entry from any state
 | 
			
		||||
            ws_bootstrap_asynch_trickle_stop(cur);
 | 
			
		||||
            //Init Packet congestion
 | 
			
		||||
            ws_bootstrap_packet_congestion_init(cur);
 | 
			
		||||
 | 
			
		||||
            if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
                tr_info("Border router start network");
 | 
			
		||||
| 
						 | 
				
			
			@ -3761,4 +3835,78 @@ int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Calculate max_packet queue size
 | 
			
		||||
static uint16_t ws_bootstrap_define_congestin_max_threshold(uint32_t heap_total_size, uint16_t packet_size, uint16_t packet_per_seconds, uint32_t max_delay, uint16_t min_packet_queue_size, uint16_t max_packet_queue_size)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t max_packet_count = 0;
 | 
			
		||||
    if (heap_total_size) {
 | 
			
		||||
        //Claculate how many packet can be max queue to half of heap
 | 
			
		||||
        max_packet_count = (heap_total_size / 2) / packet_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Calculate how many packet is possible to queue for guarantee given max delay
 | 
			
		||||
    uint32_t max_delayded_queue_size = max_delay * packet_per_seconds;
 | 
			
		||||
 | 
			
		||||
    if (max_packet_count > max_delayded_queue_size) {
 | 
			
		||||
        //Limit queue size by MAX delay
 | 
			
		||||
        max_packet_count = max_delayded_queue_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (max_packet_count > max_packet_queue_size) {
 | 
			
		||||
        //Limit queue size by Max
 | 
			
		||||
        max_packet_count = max_packet_queue_size;
 | 
			
		||||
    } else if (max_packet_count < min_packet_queue_size) {
 | 
			
		||||
        //Limit queue size by Min
 | 
			
		||||
        max_packet_count = min_packet_queue_size;
 | 
			
		||||
    }
 | 
			
		||||
    return (uint16_t)max_packet_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint16_t ws_bootstrap_packet_per_seconds(protocol_interface_info_entry_t *cur, uint16_t packet_size)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t data_rate = ws_common_datarate_get(cur);
 | 
			
		||||
 | 
			
		||||
    //calculate how many packet is possible send in paper
 | 
			
		||||
    data_rate /= 8 * packet_size;
 | 
			
		||||
 | 
			
		||||
    //Divide optimal  by / 5 because we split TX / RX slots and BC schedule
 | 
			
		||||
    //With Packet size 500 it should return
 | 
			
		||||
    //Return 15 for 300kBits
 | 
			
		||||
    //Return 7 for 150kBits
 | 
			
		||||
    //Return 2 for 50kBits
 | 
			
		||||
    return data_rate / 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    random_early_detection_free(cur->random_early_detection);
 | 
			
		||||
    cur->random_early_detection = NULL;
 | 
			
		||||
 | 
			
		||||
    //TODO implement API for HEAP info request
 | 
			
		||||
    uint32_t heap_size;
 | 
			
		||||
    const mem_stat_t *mem_stats = ns_dyn_mem_get_mem_stat();
 | 
			
		||||
    if (mem_stats) {
 | 
			
		||||
        heap_size = mem_stats->heap_sector_size;
 | 
			
		||||
    } else {
 | 
			
		||||
        heap_size = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t packet_per_seconds = ws_bootstrap_packet_per_seconds(cur, WS_CONGESTION_PACKET_SIZE);
 | 
			
		||||
 | 
			
		||||
    uint16_t min_th, max_th;
 | 
			
		||||
 | 
			
		||||
    if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
        max_th = ws_bootstrap_define_congestin_max_threshold(heap_size, WS_CONGESTION_PACKET_SIZE, packet_per_seconds, WS_CONGESTION_QUEUE_DELAY, WS_CONGESTION_BR_MIN_QUEUE_SIZE, WS_CONGESTION_BR_MAX_QUEUE_SIZE);
 | 
			
		||||
    } else {
 | 
			
		||||
        max_th = ws_bootstrap_define_congestin_max_threshold(heap_size, WS_CONGESTION_PACKET_SIZE, packet_per_seconds, WS_CONGESTION_QUEUE_DELAY, WS_CONGESTION_NODE_MIN_QUEUE_SIZE, WS_CONGESTION_NODE_MAX_QUEUE_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    min_th = max_th / 2;
 | 
			
		||||
    tr_info("Wi-SUN packet congestion minTh %u, maxTh %u, drop probability %u weight %u, Packet/Seconds %u", min_th, max_th, WS_CONGESTION_RED_DROP_PROBABILITY, RED_AVERAGE_WEIGHT_EIGHTH, packet_per_seconds);
 | 
			
		||||
    cur->random_early_detection = random_early_detection_create(min_th, max_th, WS_CONGESTION_RED_DROP_PROBABILITY, RED_AVERAGE_WEIGHT_EIGHTH);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //HAVE_WS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,6 +79,32 @@ typedef union {
 | 
			
		|||
    ws_sec_prot_cfg_t sec_prot;
 | 
			
		||||
} ws_cfgs_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct cfg_devices_in_config {
 | 
			
		||||
    uint8_t max_for_small;
 | 
			
		||||
    uint8_t max_for_medium;
 | 
			
		||||
    uint8_t max_for_large;
 | 
			
		||||
    uint8_t max_for_xlarge;
 | 
			
		||||
} cfg_devices_in_config_t;
 | 
			
		||||
 | 
			
		||||
/* Table for amount of devices that certain configuration should be used
 | 
			
		||||
 *
 | 
			
		||||
 * larger data rates allow more devices to be used with faster settings.
 | 
			
		||||
 *
 | 
			
		||||
 * For example with network the size of 2000 devices we use
 | 
			
		||||
 * Xlrage configuration with 50kbs data rate.
 | 
			
		||||
 * Large configuration with 300kbs data rate.
 | 
			
		||||
 * and with 600kbs data rate it is possible to use medium network settings.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
const cfg_devices_in_config_t devices_by_datarate[] = {
 | 
			
		||||
    { 1,  4, 10,  25}, // Configuration for 50 -100kbs
 | 
			
		||||
    { 1,  8, 15,  25}, // Configuration for 150kbs - 200kbs
 | 
			
		||||
    { 2, 15, 25,  50}, // Configuration for 300kbs
 | 
			
		||||
    { 3, 20, 40, 100}, // Configuration for 600kbs - 2400kbs
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate valid_cb, ws_cfgs_t *external_cfg, uint8_t *cfg_flags, uint8_t *flags);
 | 
			
		||||
 | 
			
		||||
static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg);
 | 
			
		||||
| 
						 | 
				
			
			@ -258,13 +284,13 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_
 | 
			
		|||
 | 
			
		||||
    ws_cfg_network_size_config_set_size set_function = NULL;
 | 
			
		||||
 | 
			
		||||
    if (cfg->network_size == NETWORK_SIZE_CERTIFICATE) {
 | 
			
		||||
    if (ws_cfg_network_config_get(cur) == CONFIG_CERTIFICATE) {
 | 
			
		||||
        set_function = ws_cfg_network_size_config_set_certificate;
 | 
			
		||||
    } else if (cfg->network_size <= NETWORK_SIZE_SMALL || cfg->network_size == NETWORK_SIZE_AUTOMATIC) {
 | 
			
		||||
    } else if (ws_cfg_network_config_get(cur) == CONFIG_SMALL || cfg->network_size == NETWORK_SIZE_AUTOMATIC) {
 | 
			
		||||
        set_function = ws_cfg_network_size_config_set_small;
 | 
			
		||||
    } else if (cfg->network_size <=  NETWORK_SIZE_MEDIUM) {
 | 
			
		||||
    } else if (ws_cfg_network_config_get(cur) == CONFIG_MEDIUM) {
 | 
			
		||||
        set_function = ws_cfg_network_size_config_set_medium;
 | 
			
		||||
    } else if (cfg->network_size <=  NETWORK_SIZE_LARGE) {
 | 
			
		||||
    } else if (ws_cfg_network_config_get(cur) == CONFIG_LARGE) {
 | 
			
		||||
        set_function = ws_cfg_network_size_config_set_large;
 | 
			
		||||
    } else {
 | 
			
		||||
        set_function = ws_cfg_network_size_config_set_xlarge;
 | 
			
		||||
| 
						 | 
				
			
			@ -360,6 +386,47 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1
 | 
			
		|||
    return CFG_SETTINGS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cfg_network_size_type_e ws_cfg_network_config_get(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    // Get size of the network Amount of devices in the network
 | 
			
		||||
    // Get the data rate of the network
 | 
			
		||||
    // Adjust the configuration type based on the network size and data rate
 | 
			
		||||
 | 
			
		||||
    (void)cur;
 | 
			
		||||
 | 
			
		||||
    ws_gen_cfg_t cfg;
 | 
			
		||||
    if (ws_cfg_gen_get(&cfg, NULL) < 0) {
 | 
			
		||||
        return CONFIG_SMALL;
 | 
			
		||||
    }
 | 
			
		||||
    ws_phy_cfg_t phy_cfg;
 | 
			
		||||
    if (ws_cfg_phy_get(&phy_cfg, NULL) < 0) {
 | 
			
		||||
        return CONFIG_SMALL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t data_rate = ws_get_datarate_using_operating_mode(phy_cfg.operating_mode);
 | 
			
		||||
    uint8_t index;
 | 
			
		||||
    if (data_rate < 150000) {
 | 
			
		||||
        index = 0;
 | 
			
		||||
    } else if (data_rate < 300000) {
 | 
			
		||||
        index = 1;
 | 
			
		||||
    } else if (data_rate < 600000) {
 | 
			
		||||
        index = 2;
 | 
			
		||||
    } else {
 | 
			
		||||
        index = 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cfg.network_size == NETWORK_SIZE_CERTIFICATE) {
 | 
			
		||||
        return CONFIG_CERTIFICATE;
 | 
			
		||||
    } else if (cfg.network_size <= devices_by_datarate[index].max_for_small) {
 | 
			
		||||
        return CONFIG_SMALL;
 | 
			
		||||
    } else if (cfg.network_size <= devices_by_datarate[index].max_for_medium) {
 | 
			
		||||
        return CONFIG_MEDIUM;
 | 
			
		||||
    } else if (cfg.network_size <= devices_by_datarate[index].max_for_large) {
 | 
			
		||||
        return CONFIG_LARGE;
 | 
			
		||||
    }
 | 
			
		||||
    return CONFIG_XLARGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -651,6 +718,8 @@ int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg)
 | 
			
		|||
    cfg->regulatory_domain = REG_DOMAIN_EU;
 | 
			
		||||
    cfg->operating_mode = OPERATING_MODE_3;
 | 
			
		||||
    cfg->operating_class = 2;
 | 
			
		||||
    cfg->phy_mode_id = 255;
 | 
			
		||||
    cfg->channel_plan_id = 255;
 | 
			
		||||
 | 
			
		||||
    return CFG_SETTINGS_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -671,12 +740,16 @@ int8_t ws_cfg_phy_validate(ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg)
 | 
			
		|||
    // Regulator domain, operating mode or class has changed
 | 
			
		||||
    if (cfg->regulatory_domain != new_cfg->regulatory_domain ||
 | 
			
		||||
            cfg->operating_mode != new_cfg->operating_mode ||
 | 
			
		||||
            cfg->operating_class != new_cfg->operating_class) {
 | 
			
		||||
            cfg->operating_class != new_cfg->operating_class ||
 | 
			
		||||
            cfg->phy_mode_id != new_cfg->phy_mode_id ||
 | 
			
		||||
            cfg->channel_plan_id != new_cfg->channel_plan_id) {
 | 
			
		||||
 | 
			
		||||
        ws_hopping_schedule_t hopping_schdule = {
 | 
			
		||||
            .regulatory_domain = new_cfg->regulatory_domain,
 | 
			
		||||
            .operating_mode = new_cfg->operating_mode,
 | 
			
		||||
            .operating_class = new_cfg->operating_class
 | 
			
		||||
            .operating_class = new_cfg->operating_class,
 | 
			
		||||
            .phy_mode_id = new_cfg->phy_mode_id,
 | 
			
		||||
            .channel_plan_id = new_cfg->channel_plan_id
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Check that new settings are valid
 | 
			
		||||
| 
						 | 
				
			
			@ -698,11 +771,31 @@ int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, w
 | 
			
		|||
    if (ret != CFG_SETTINGS_CHANGED) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check settings and configure interface
 | 
			
		||||
    if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) {
 | 
			
		||||
        // Set operating mode for FSK if given with PHY mode ID
 | 
			
		||||
        if ((new_cfg->phy_mode_id == 1) || (new_cfg->phy_mode_id == 17)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_1a;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 2) || (new_cfg->phy_mode_id == 18)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_1b;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 3) || (new_cfg->phy_mode_id == 19)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_2a;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 4) || (new_cfg->phy_mode_id == 20)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_2b;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 5) || (new_cfg->phy_mode_id == 21)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 6) || (new_cfg->phy_mode_id == 22)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_4a;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 7) || (new_cfg->phy_mode_id == 23)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_4b;
 | 
			
		||||
        } else if ((new_cfg->phy_mode_id == 8) || (new_cfg->phy_mode_id == 24)) {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_5;
 | 
			
		||||
        } else {
 | 
			
		||||
            cur->ws_info->hopping_schdule.operating_mode = new_cfg->operating_mode;
 | 
			
		||||
        }
 | 
			
		||||
        cur->ws_info->hopping_schdule.phy_mode_id = new_cfg->phy_mode_id;
 | 
			
		||||
        cur->ws_info->hopping_schdule.channel_plan_id = new_cfg->channel_plan_id;
 | 
			
		||||
        cur->ws_info->hopping_schdule.regulatory_domain = new_cfg->regulatory_domain;
 | 
			
		||||
        cur->ws_info->hopping_schdule.operating_mode = new_cfg->operating_mode;
 | 
			
		||||
        cur->ws_info->hopping_schdule.operating_class = new_cfg->operating_class;
 | 
			
		||||
 | 
			
		||||
        if (ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule) < 0) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,8 @@ typedef struct ws_phy_cfg_s {
 | 
			
		|||
    uint8_t regulatory_domain;          /**< PHY regulatory domain; default "KR" 0x09 */
 | 
			
		||||
    uint8_t operating_class;            /**< PHY operating class; default 1 */
 | 
			
		||||
    uint8_t operating_mode;             /**< PHY operating mode; default "1b" symbol rate 50, modulation index 1 */
 | 
			
		||||
    uint8_t phy_mode_id;                /**< PHY mode ID; default 255 (not used) */
 | 
			
		||||
    uint8_t channel_plan_id;            /**< Channel plan ID; default 255 (not used) */
 | 
			
		||||
} ws_phy_cfg_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -146,11 +148,23 @@ typedef struct ws_cfg_s {
 | 
			
		|||
#define CFG_SETTINGS_ERROR_SEC_TIMER_CONF    -17   /**< Security timers configuration error */
 | 
			
		||||
#define CFG_SETTINGS_ERROR_SEC_PROT_CONF     -18   /**< Security protocols configuration error */
 | 
			
		||||
 | 
			
		||||
/** Network configuration parameters sets for different network sizes*/
 | 
			
		||||
typedef enum {
 | 
			
		||||
    CONFIG_CERTIFICATE = 0,  ///< Configuration used in Wi-SUN Certification
 | 
			
		||||
    CONFIG_SMALL = 1,        ///< Small networks that can utilize fast recovery
 | 
			
		||||
    CONFIG_MEDIUM = 2,       ///< Medium networks that can form quickly but require balance on load
 | 
			
		||||
    CONFIG_LARGE = 3,        ///< Large networks that needs to throttle joining and maintenance
 | 
			
		||||
    CONFIG_XLARGE = 4        ///< Xlarge networks with very slow joining, maintenance and recovery profile
 | 
			
		||||
} cfg_network_size_type_e;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int8_t ws_cfg_settings_init(void);
 | 
			
		||||
int8_t ws_cfg_settings_default_set(void);
 | 
			
		||||
int8_t ws_cfg_settings_interface_set(protocol_interface_info_entry_t *cur);
 | 
			
		||||
int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint16_t network_size);
 | 
			
		||||
 | 
			
		||||
cfg_network_size_type_e ws_cfg_network_config_get(protocol_interface_info_entry_t *cur);
 | 
			
		||||
 | 
			
		||||
int8_t ws_cfg_network_size_get(ws_gen_cfg_t *cfg, uint8_t *flags);
 | 
			
		||||
int8_t ws_cfg_network_size_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg);
 | 
			
		||||
int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg, uint8_t *flags);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,33 +53,57 @@ uint8_t DEVICE_MIN_SENS = 174 - 93;
 | 
			
		|||
 | 
			
		||||
uint16_t test_max_child_count_override = 0xffff;
 | 
			
		||||
 | 
			
		||||
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class)
 | 
			
		||||
static int8_t ws_disable_channels_in_range(uint32_t *channel_mask, uint16_t number_of_channels, uint16_t range_start, uint16_t range_stop)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t excluded_start_channel = 0xFFFFFFFF;
 | 
			
		||||
    uint32_t excluded_end_channel = 0xFFFFFFFF;
 | 
			
		||||
 | 
			
		||||
    if (regulatory_domain == REG_DOMAIN_BZ) {
 | 
			
		||||
        if (operating_class == 1) {
 | 
			
		||||
            excluded_start_channel = 26;
 | 
			
		||||
            excluded_end_channel = 64;
 | 
			
		||||
        } else if (operating_class == 2) {
 | 
			
		||||
            excluded_start_channel = 12;
 | 
			
		||||
            excluded_end_channel = 32;
 | 
			
		||||
        } else if (operating_class == 3) {
 | 
			
		||||
            excluded_start_channel = 7;
 | 
			
		||||
            excluded_end_channel = 21;
 | 
			
		||||
    for (uint16_t i = 0; i < number_of_channels; i++) {
 | 
			
		||||
        if (i >= range_start && i <= range_stop) {
 | 
			
		||||
            channel_mask[0 + (i / 32)] &= ~(1 << (i % 32));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id)
 | 
			
		||||
{
 | 
			
		||||
    // Clear channel mask
 | 
			
		||||
    for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
        channel_mask[i] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Set channel maks outside excluded channels
 | 
			
		||||
    // Enable all channels
 | 
			
		||||
    for (uint16_t i = 0; i < number_of_channels; i++) {
 | 
			
		||||
        if (i < excluded_start_channel || i > excluded_end_channel) {
 | 
			
		||||
            channel_mask[0 + (i / 32)] |= (1 << (i % 32));
 | 
			
		||||
        channel_mask[0 + (i / 32)] |= (1 << (i % 32));
 | 
			
		||||
    }
 | 
			
		||||
    // Disable unsupported channels per regional frequency bands
 | 
			
		||||
    if (regulatory_domain == REG_DOMAIN_NA) {
 | 
			
		||||
        if (channel_plan_id == 1) {
 | 
			
		||||
            ws_disable_channels_in_range(channel_mask, number_of_channels, 1, 7);
 | 
			
		||||
        } else if (channel_plan_id == 5) {
 | 
			
		||||
            ws_disable_channels_in_range(channel_mask, number_of_channels, 5, 7);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (regulatory_domain == REG_DOMAIN_BZ) {
 | 
			
		||||
        if (channel_plan_id == 255) {
 | 
			
		||||
            if (operating_class == 1) {
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 26, 64);
 | 
			
		||||
            } else if (operating_class == 2) {
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 12, 32);
 | 
			
		||||
            } else if (operating_class == 3) {
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 7, 21);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (channel_plan_id == 1) {
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 1, 7);
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 64, 64);
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 72, 103);
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 106, 111);
 | 
			
		||||
            } else if (channel_plan_id == 2) {
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 24, 24);
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 32, 47);
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 52, 55);
 | 
			
		||||
            } else if (channel_plan_id == 5) {
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 5, 10);
 | 
			
		||||
                ws_disable_channels_in_range(channel_mask, number_of_channels, 19, 23);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +133,10 @@ uint32_t ws_decode_channel_spacing(uint8_t channel_spacing)
 | 
			
		|||
        return 400000;
 | 
			
		||||
    } else if (CHANNEL_SPACING_600 == channel_spacing) {
 | 
			
		||||
        return 600000;
 | 
			
		||||
    } else if (CHANNEL_SPACING_800 == channel_spacing) {
 | 
			
		||||
        return 800000;
 | 
			
		||||
    } else if (CHANNEL_SPACING_1200 == channel_spacing) {
 | 
			
		||||
        return 1200000;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -129,6 +157,60 @@ uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t ws_get_datarate_using_phy_mode_id(uint8_t phy_mode_id)
 | 
			
		||||
{
 | 
			
		||||
    if (84 == phy_mode_id) {
 | 
			
		||||
        return 150000;
 | 
			
		||||
    } else if (85 == phy_mode_id) {
 | 
			
		||||
        return 200000;
 | 
			
		||||
    } else if ((68 == phy_mode_id) || (86 == phy_mode_id)) {
 | 
			
		||||
        return 300000;
 | 
			
		||||
    } else if ((34 == phy_mode_id) || (51 == phy_mode_id) || (69 == phy_mode_id)) {
 | 
			
		||||
        return 400000;
 | 
			
		||||
    } else if ((52 == phy_mode_id) || (70 == phy_mode_id)) {
 | 
			
		||||
        return 600000;
 | 
			
		||||
    } else if ((35 == phy_mode_id) || (53 == phy_mode_id)) {
 | 
			
		||||
        return 800000;
 | 
			
		||||
    } else if ((36 == phy_mode_id) || (54 == phy_mode_id)) {
 | 
			
		||||
        return 1200000;
 | 
			
		||||
    } else if (37 == phy_mode_id) {
 | 
			
		||||
        return 1600000;
 | 
			
		||||
    } else if (38 == phy_mode_id) {
 | 
			
		||||
        return 2400000;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ws_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id)
 | 
			
		||||
{
 | 
			
		||||
    if ((phy_mode_id >= 34) && (phy_mode_id <= 38)) {
 | 
			
		||||
        return OFDM_OPTION_1;
 | 
			
		||||
    } else if ((phy_mode_id >= 51) && (phy_mode_id <= 54)) {
 | 
			
		||||
        return OFDM_OPTION_2;
 | 
			
		||||
    } else if ((phy_mode_id >= 68) && (phy_mode_id <= 70)) {
 | 
			
		||||
        return OFDM_OPTION_3;
 | 
			
		||||
    } else if ((phy_mode_id >= 84) && (phy_mode_id <= 86)) {
 | 
			
		||||
        return OFDM_OPTION_4;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ws_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id)
 | 
			
		||||
{
 | 
			
		||||
    if (34 == phy_mode_id) {
 | 
			
		||||
        return OFDM_MCS_2;
 | 
			
		||||
    } else if ((35 == phy_mode_id) || (51 == phy_mode_id)) {
 | 
			
		||||
        return OFDM_MCS_3;
 | 
			
		||||
    } else if ((36 == phy_mode_id) || (52 == phy_mode_id) || (68 == phy_mode_id) || (84 == phy_mode_id)) {
 | 
			
		||||
        return OFDM_MCS_4;
 | 
			
		||||
    } else if ((37 == phy_mode_id) || (53 == phy_mode_id) || (69 == phy_mode_id) || (85 == phy_mode_id)) {
 | 
			
		||||
        return OFDM_MCS_5;
 | 
			
		||||
    } else if ((38 == phy_mode_id) || (54 == phy_mode_id) || (70 == phy_mode_id) || (86 == phy_mode_id)) {
 | 
			
		||||
        return OFDM_MCS_6;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode)
 | 
			
		||||
{
 | 
			
		||||
    if ((OPERATING_MODE_1b == operating_mode) || (OPERATING_MODE_2b == operating_mode) || (OPERATING_MODE_4b == operating_mode)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -146,6 +228,38 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur,
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Validate PHY mode ID
 | 
			
		||||
    if (hopping_schdule->phy_mode_id != 255) {
 | 
			
		||||
        uint8_t phy_mode_id = hopping_schdule->phy_mode_id;
 | 
			
		||||
        uint8_t phy_type = phy_mode_id >> 4;
 | 
			
		||||
        uint8_t phy_mode = phy_mode_id & 0x0f;
 | 
			
		||||
        // Invalid PHY type
 | 
			
		||||
        if (phy_type > 5) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        // Invalid OFDM mode
 | 
			
		||||
        if (phy_type >= 2 && phy_mode > 6) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        // Skip if PHY mode is for FSK modulation
 | 
			
		||||
        if (!phy_mode_id || ((phy_mode_id > 8) && (phy_mode_id < 17)) || phy_mode_id > 24) {
 | 
			
		||||
            // Validate OFDM configurations
 | 
			
		||||
            if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) ||
 | 
			
		||||
                    ((phy_mode_id >= 51) && (phy_mode_id <= 54)) ||
 | 
			
		||||
                    ((phy_mode_id >= 68) && (phy_mode_id <= 70)) ||
 | 
			
		||||
                    ((phy_mode_id >= 84) && (phy_mode_id <= 86))) {
 | 
			
		||||
                if (ws_get_datarate_using_phy_mode_id(phy_mode_id) == 0 ||
 | 
			
		||||
                        ws_get_ofdm_option_using_phy_mode_id(phy_mode_id) == 0 ||
 | 
			
		||||
                        ws_get_ofdm_mcs_using_phy_mode_id(phy_mode_id) == 0) {
 | 
			
		||||
                    //Unsupported PHY mode
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // Invalid PHY mode ID
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    hopping_schdule->channel_plan = 0;
 | 
			
		||||
 | 
			
		||||
    if (hopping_schdule->regulatory_domain == REG_DOMAIN_KR) {
 | 
			
		||||
| 
						 | 
				
			
			@ -185,30 +299,60 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur,
 | 
			
		|||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_NA) {
 | 
			
		||||
        if (hopping_schdule->operating_class == 1) {
 | 
			
		||||
            hopping_schdule->ch0_freq = 9022;
 | 
			
		||||
            hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
 | 
			
		||||
        } else if (hopping_schdule->operating_class == 2) {
 | 
			
		||||
            hopping_schdule->ch0_freq = 9024;
 | 
			
		||||
            hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
 | 
			
		||||
        } else if (hopping_schdule->operating_class == 3) {
 | 
			
		||||
            hopping_schdule->ch0_freq = 9026;
 | 
			
		||||
            hopping_schdule->channel_spacing = CHANNEL_SPACING_600;
 | 
			
		||||
        if (hopping_schdule->channel_plan_id == 255) {
 | 
			
		||||
            if (hopping_schdule->operating_class == 1) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9022;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
 | 
			
		||||
            } else if (hopping_schdule->operating_class == 2) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9024;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
 | 
			
		||||
            } else if (hopping_schdule->operating_class == 3) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9026;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_600;
 | 
			
		||||
            } else {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1;
 | 
			
		||||
            if (hopping_schdule->channel_plan_id == 1) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9022;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
 | 
			
		||||
            } else if (hopping_schdule->channel_plan_id == 2) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9024;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
 | 
			
		||||
            } else if (hopping_schdule->channel_plan_id == 5) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9032;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_1200;
 | 
			
		||||
            } else {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_BZ) {
 | 
			
		||||
        if (hopping_schdule->operating_class == 1) {
 | 
			
		||||
            hopping_schdule->ch0_freq = 9022;
 | 
			
		||||
            hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
 | 
			
		||||
        } else if (hopping_schdule->operating_class == 2) {
 | 
			
		||||
            hopping_schdule->ch0_freq = 9024;
 | 
			
		||||
            hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
 | 
			
		||||
        } else if (hopping_schdule->operating_class == 3) {
 | 
			
		||||
            hopping_schdule->ch0_freq = 9026;
 | 
			
		||||
            hopping_schdule->channel_spacing = CHANNEL_SPACING_600;
 | 
			
		||||
        if (hopping_schdule->channel_plan_id == 255) {
 | 
			
		||||
            if (hopping_schdule->operating_class == 1) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9022;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
 | 
			
		||||
            } else if (hopping_schdule->operating_class == 2) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9024;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
 | 
			
		||||
            } else if (hopping_schdule->operating_class == 3) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9026;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_600;
 | 
			
		||||
            } else {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1;
 | 
			
		||||
            if (hopping_schdule->channel_plan_id == 1) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9022;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
 | 
			
		||||
            } else if (hopping_schdule->channel_plan_id == 2) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9024;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
 | 
			
		||||
            } else if (hopping_schdule->channel_plan_id == 5) {
 | 
			
		||||
                hopping_schdule->ch0_freq = 9032;
 | 
			
		||||
                hopping_schdule->channel_spacing = CHANNEL_SPACING_1200;
 | 
			
		||||
            } else {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_JP) {
 | 
			
		||||
        if (hopping_schdule->operating_class == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -236,7 +380,7 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur,
 | 
			
		|||
    } else {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    hopping_schdule->number_of_channels = (uint8_t)ws_common_channel_number_calc(hopping_schdule->regulatory_domain, hopping_schdule->operating_class);
 | 
			
		||||
    hopping_schdule->number_of_channels = (uint8_t)ws_common_channel_number_calc(hopping_schdule->regulatory_domain, hopping_schdule->operating_class, hopping_schdule->channel_plan_id);
 | 
			
		||||
    if (!hopping_schdule->number_of_channels) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +388,7 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur,
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operating_class)
 | 
			
		||||
uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id)
 | 
			
		||||
{
 | 
			
		||||
    if (regulatory_domain == REG_DOMAIN_KR) {
 | 
			
		||||
        if (operating_class == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -269,12 +413,22 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat
 | 
			
		|||
            return 10;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (regulatory_domain == REG_DOMAIN_NA) {
 | 
			
		||||
        if (operating_class == 1) {
 | 
			
		||||
            return 129;
 | 
			
		||||
        } else if (operating_class == 2) {
 | 
			
		||||
            return 64;
 | 
			
		||||
        } else if (operating_class == 3) {
 | 
			
		||||
            return 42;
 | 
			
		||||
        if (channel_plan_id == 255) {
 | 
			
		||||
            if (operating_class == 1) {
 | 
			
		||||
                return 129;
 | 
			
		||||
            } else if (operating_class == 2) {
 | 
			
		||||
                return 64;
 | 
			
		||||
            } else if (operating_class == 3) {
 | 
			
		||||
                return 42;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (channel_plan_id == 1) {
 | 
			
		||||
                return 136;
 | 
			
		||||
            } else if (channel_plan_id == 2) {
 | 
			
		||||
                return 64;
 | 
			
		||||
            } else if (channel_plan_id == 5) {
 | 
			
		||||
                return 24;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if (regulatory_domain == REG_DOMAIN_JP) {
 | 
			
		||||
        if (operating_class == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -285,12 +439,22 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat
 | 
			
		|||
            return 12;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (regulatory_domain == REG_DOMAIN_BZ) {
 | 
			
		||||
        if (operating_class == 1) {
 | 
			
		||||
            return 129;
 | 
			
		||||
        } else if (operating_class == 2) {
 | 
			
		||||
            return 64;
 | 
			
		||||
        } else if (operating_class == 3) {
 | 
			
		||||
            return 42;
 | 
			
		||||
        if (channel_plan_id == 255) {
 | 
			
		||||
            if (operating_class == 1) {
 | 
			
		||||
                return 129;
 | 
			
		||||
            } else if (operating_class == 2) {
 | 
			
		||||
                return 64;
 | 
			
		||||
            } else if (operating_class == 3) {
 | 
			
		||||
                return 42;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (channel_plan_id == 1) {
 | 
			
		||||
                return 136;
 | 
			
		||||
            } else if (channel_plan_id == 2) {
 | 
			
		||||
                return 64;
 | 
			
		||||
            } else if (channel_plan_id == 5) {
 | 
			
		||||
                return 24;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if (regulatory_domain == REG_DOMAIN_WW) {
 | 
			
		||||
        if (operating_class == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -366,10 +530,16 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_common_black_list_neighbour(const uint8_t *ll_address, uint8_t nd_status)
 | 
			
		||||
{
 | 
			
		||||
    if (nd_status == ARO_FULL) {
 | 
			
		||||
        blacklist_update(ll_address, false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
 | 
			
		||||
{
 | 
			
		||||
    tr_warn("ARO registration Failure %s", trace_ipv6(ll_address));
 | 
			
		||||
    blacklist_update(ll_address, false);
 | 
			
		||||
    ws_bootstrap_aro_failure(cur, ll_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -390,29 +560,41 @@ uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_common_neighbour_address_reg_link_update(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
 | 
			
		||||
static void ws_common_neighbour_address_reg_link_update(protocol_interface_info_entry_t *interface, const uint8_t *eui64, uint32_t link_lifetime)
 | 
			
		||||
{
 | 
			
		||||
    if (link_lifetime > WS_NEIGHBOR_LINK_TIMEOUT) {
 | 
			
		||||
        link_lifetime = WS_NEIGHBOR_LINK_TIMEOUT;
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
     * ARO registration from child can update the link timeout so we don't need to send extra NUD if ARO received
 | 
			
		||||
     */
 | 
			
		||||
    mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_by_mac64(mac_neighbor_info(interface), eui64, false, false);
 | 
			
		||||
 | 
			
		||||
    if (mac_neighbor) {
 | 
			
		||||
        if (mac_neighbor->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) {
 | 
			
		||||
        if (mac_neighbor->link_lifetime < link_lifetime) {
 | 
			
		||||
            //Set Stable timeout for temporary entry here
 | 
			
		||||
            if (link_lifetime > WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME && mac_neighbor->link_lifetime  < WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) {
 | 
			
		||||
                tr_info("Added new neighbor %s : index:%u", trace_array(eui64, 8), mac_neighbor->index);
 | 
			
		||||
            }
 | 
			
		||||
            mac_neighbor->link_lifetime = WS_NEIGHBOR_LINK_TIMEOUT;
 | 
			
		||||
            tr_info("Added new neighbor %s : index:%u", trace_array(eui64, 8), mac_neighbor->index);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        //Refresh
 | 
			
		||||
        mac_neighbor->lifetime = mac_neighbor->link_lifetime;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
 | 
			
		||||
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64, uint16_t aro_timeout)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t child_count = 0;
 | 
			
		||||
    uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - ws_common_temporary_entry_size(mac_neighbor_info(interface)->list_total_size);
 | 
			
		||||
 | 
			
		||||
    if (aro_timeout == 0) {
 | 
			
		||||
        //DeRegister Address Reg
 | 
			
		||||
        return ARO_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t link_lifetime = (aro_timeout * 60) + 1;
 | 
			
		||||
 | 
			
		||||
    // Test API to limit child count
 | 
			
		||||
    if (test_max_child_count_override != 0xffff) {
 | 
			
		||||
        max_child_count = test_max_child_count_override;
 | 
			
		||||
| 
						 | 
				
			
			@ -420,8 +602,9 @@ uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *inte
 | 
			
		|||
 | 
			
		||||
    //Validate Is EUI64 already allocated for any address
 | 
			
		||||
    if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, eui64)) {
 | 
			
		||||
        ws_common_neighbour_address_reg_link_update(interface, eui64);
 | 
			
		||||
        ws_common_neighbour_address_reg_link_update(interface, eui64, link_lifetime);
 | 
			
		||||
        tr_info("Child registration from old child");
 | 
			
		||||
 | 
			
		||||
        return ARO_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -431,20 +614,21 @@ uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *inte
 | 
			
		|||
        return ARO_TOPOLOGICALLY_INCORRECT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) {
 | 
			
		||||
 | 
			
		||||
        if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) {
 | 
			
		||||
            child_count++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (child_count >= max_child_count) {
 | 
			
		||||
        tr_warn("Child registration not allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size);
 | 
			
		||||
        return ARO_FULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_common_neighbour_address_reg_link_update(interface, eui64);
 | 
			
		||||
    ws_common_neighbour_address_reg_link_update(interface, eui64, link_lifetime);
 | 
			
		||||
    tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size);
 | 
			
		||||
 | 
			
		||||
    return ARO_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -464,21 +648,16 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con
 | 
			
		|||
uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t latency = 0;
 | 
			
		||||
    uint8_t network_size = cur->ws_info->cfg->gen.network_size;
 | 
			
		||||
 | 
			
		||||
    if (network_size == NETWORK_SIZE_AUTOMATIC) {
 | 
			
		||||
        network_size = cur->ws_info->pan_information.pan_size / 100;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (network_size <= NETWORK_SIZE_SMALL) {
 | 
			
		||||
        // handles also NETWORK_SIZE_CERTIFICATE
 | 
			
		||||
        latency = 4000;
 | 
			
		||||
    } else if (network_size <= NETWORK_SIZE_MEDIUM) {
 | 
			
		||||
        latency = 8000;
 | 
			
		||||
    } else if (network_size <= NETWORK_SIZE_LARGE) {
 | 
			
		||||
        latency = 16000;
 | 
			
		||||
    if (ws_cfg_network_config_get(cur) <= CONFIG_SMALL) {
 | 
			
		||||
        // Also has the certificate settings
 | 
			
		||||
        latency = 5000;
 | 
			
		||||
    } else if (ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM) {
 | 
			
		||||
        latency = 10000;
 | 
			
		||||
    } else if (ws_cfg_network_config_get(cur) <= CONFIG_LARGE) {
 | 
			
		||||
        latency = 20000;
 | 
			
		||||
    } else  {
 | 
			
		||||
        latency = 24000;
 | 
			
		||||
        latency = 30000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return latency;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ typedef struct ws_info_s {
 | 
			
		|||
 | 
			
		||||
#ifdef HAVE_WS
 | 
			
		||||
 | 
			
		||||
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class);
 | 
			
		||||
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id);
 | 
			
		||||
 | 
			
		||||
uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,11 +130,17 @@ uint32_t ws_decode_channel_spacing(uint8_t channel_spacing);
 | 
			
		|||
 | 
			
		||||
uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode);
 | 
			
		||||
 | 
			
		||||
uint32_t ws_get_datarate_using_phy_mode_id(uint8_t phy_mode_id);
 | 
			
		||||
 | 
			
		||||
uint8_t ws_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id);
 | 
			
		||||
 | 
			
		||||
uint8_t ws_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id);
 | 
			
		||||
 | 
			
		||||
phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode);
 | 
			
		||||
 | 
			
		||||
int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, ws_hopping_schedule_t *hopping_schdule);
 | 
			
		||||
 | 
			
		||||
uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operating_class);
 | 
			
		||||
uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id);
 | 
			
		||||
 | 
			
		||||
int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -144,11 +150,13 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks);
 | 
			
		|||
 | 
			
		||||
void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
 | 
			
		||||
 | 
			
		||||
void ws_common_black_list_neighbour(const uint8_t *ll_address, uint8_t nd_status);
 | 
			
		||||
 | 
			
		||||
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
 | 
			
		||||
 | 
			
		||||
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
 | 
			
		||||
 | 
			
		||||
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
 | 
			
		||||
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64, uint16_t aro_timeout);
 | 
			
		||||
 | 
			
		||||
bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -170,10 +178,11 @@ uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size);
 | 
			
		|||
#define ws_info(cur) ((ws_info_t *) NULL)
 | 
			
		||||
#define ws_common_seconds_timer(cur, seconds)
 | 
			
		||||
#define ws_common_neighbor_update(cur, ll_address) ((void) 0)
 | 
			
		||||
#define ws_common_black_list_neighbour(ll_address, nd_status) ((void) 0)
 | 
			
		||||
#define ws_common_aro_failure(cur, ll_address)
 | 
			
		||||
#define ws_common_neighbor_remove(cur, ll_address)
 | 
			
		||||
#define ws_common_fast_timer(cur, ticks) ((void) 0)
 | 
			
		||||
#define ws_common_allow_child_registration(cur, eui64) (2)
 | 
			
		||||
#define ws_common_allow_child_registration(cur, eui64, aro_timeout) (2)
 | 
			
		||||
#define ws_common_negative_aro_mark(interface, eui64)(false)
 | 
			
		||||
#define ws_common_latency_estimate_get(cur) 0
 | 
			
		||||
#define ws_common_datarate_get(cur) 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,6 +100,8 @@ typedef struct ws_hopping_schedule_s {
 | 
			
		|||
    uint8_t regulatory_domain;          /**< PHY regulatory domain default to "KR" 0x09 */
 | 
			
		||||
    uint8_t operating_class;            /**< PHY operating class default to 1 */
 | 
			
		||||
    uint8_t operating_mode;             /**< PHY operating mode default to "1b" symbol rate 50, modulation index 1 */
 | 
			
		||||
    uint8_t phy_mode_id;                /**< PHY mode ID, default to 255 */
 | 
			
		||||
    uint8_t channel_plan_id;            /**< Channel plan ID, default to 255 */
 | 
			
		||||
    uint8_t channel_plan;               /**< 0: use regulatory domain values 1: application defined plan */
 | 
			
		||||
    uint8_t uc_channel_function;        /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */
 | 
			
		||||
    uint8_t bc_channel_function;        /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,9 +144,9 @@ extern uint8_t DEVICE_MIN_SENS;
 | 
			
		|||
#define MPL_SMALL_K 8
 | 
			
		||||
#define MPL_SMALL_SEED_LIFETIME (MPL_SMALL_IMAX * MPL_SAFE_HOP_COUNT * (MPL_SMALL_EXPIRATIONS + 1)) // time that packet should get to safe distance
 | 
			
		||||
/*Medium network size*/
 | 
			
		||||
#define MPL_MEDIUM_IMIN 5
 | 
			
		||||
#define MPL_MEDIUM_IMAX 20
 | 
			
		||||
#define MPL_MEDIUM_EXPIRATIONS 2
 | 
			
		||||
#define MPL_MEDIUM_IMIN 1
 | 
			
		||||
#define MPL_MEDIUM_IMAX 32
 | 
			
		||||
#define MPL_MEDIUM_EXPIRATIONS 1
 | 
			
		||||
#define MPL_MEDIUM_K 8
 | 
			
		||||
#define MPL_MEDIUM_SEED_LIFETIME (MPL_MEDIUM_IMAX * MPL_SAFE_HOP_COUNT * (MPL_MEDIUM_EXPIRATIONS + 1)) // time that packet should get to safe distance
 | 
			
		||||
/*Large network size*/
 | 
			
		||||
| 
						 | 
				
			
			@ -221,6 +221,13 @@ extern uint8_t DEVICE_MIN_SENS;
 | 
			
		|||
#define WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY 5  // During discovery state how many neighbours per pan
 | 
			
		||||
#define WS_PARENT_LIST_MAX_PAN_IN_ACTIVE 2     // During active state two nodes per pan is allowed
 | 
			
		||||
 | 
			
		||||
#define WS_CONGESTION_PACKET_SIZE 500           // Packet length for calculate how much heap message queue can fit
 | 
			
		||||
#define WS_CONGESTION_QUEUE_DELAY 60            // Define message queue max length for given delay. This value is multiple by packet/seconds
 | 
			
		||||
#define WS_CONGESTION_RED_DROP_PROBABILITY 10 //10.0%
 | 
			
		||||
#define WS_CONGESTION_BR_MIN_QUEUE_SIZE 85000 / WS_CONGESTION_PACKET_SIZE
 | 
			
		||||
#define WS_CONGESTION_BR_MAX_QUEUE_SIZE 600000 / WS_CONGESTION_PACKET_SIZE
 | 
			
		||||
#define WS_CONGESTION_NODE_MIN_QUEUE_SIZE 10000 / WS_CONGESTION_PACKET_SIZE
 | 
			
		||||
#define WS_CONGESTION_NODE_MAX_QUEUE_SIZE 85000 / WS_CONGESTION_PACKET_SIZE
 | 
			
		||||
/*
 | 
			
		||||
 * Modifications for base specification.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
#include "mac_api.h"
 | 
			
		||||
#include "mac_mcps.h"
 | 
			
		||||
#include "Common_Protocols/ipv6_constants.h"
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
#include "socket_api.h"
 | 
			
		||||
#include "6LoWPAN/MAC/mac_helper.h"
 | 
			
		||||
#include "6LoWPAN/MAC/mpx_api.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +81,8 @@ int8_t ws_eapol_auth_relay_start(protocol_interface_info_entry_t *interface_ptr,
 | 
			
		|||
        ns_dyn_mem_free(eapol_auth_relay);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    int16_t tc = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
    socket_setsockopt(eapol_auth_relay->socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc));
 | 
			
		||||
 | 
			
		||||
    ns_list_add_to_end(&eapol_auth_relay_list, eapol_auth_relay);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -278,6 +278,9 @@ static void ws_eapol_pdu_mpx_data_confirm(const mpx_api_t *api, const struct mcp
 | 
			
		|||
                    status = EAPOL_PDU_TX_OK;
 | 
			
		||||
                } else if (data->status == MLME_TX_NO_ACK) {
 | 
			
		||||
                    status = EAPOL_PDU_TX_ERR_TX_NO_ACK;
 | 
			
		||||
                    tr_error("EAPOL TX err no ack");
 | 
			
		||||
                } else {
 | 
			
		||||
                    tr_error("EAPOL TX err");
 | 
			
		||||
                }
 | 
			
		||||
                msdu->tx_status(eapol_pdu_data->interface_ptr, status, msdu->tx_identifier);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
#include "mac_api.h"
 | 
			
		||||
#include "mac_mcps.h"
 | 
			
		||||
#include "Common_Protocols/ipv6_constants.h"
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
#include "socket_api.h"
 | 
			
		||||
#include "6LoWPAN/MAC/mac_helper.h"
 | 
			
		||||
#include "6LoWPAN/MAC/mpx_api.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +90,8 @@ int8_t ws_eapol_relay_start(protocol_interface_info_entry_t *interface_ptr, uint
 | 
			
		|||
        ns_dyn_mem_free(eapol_relay);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    int16_t tc = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
    socket_setsockopt(eapol_relay->socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc));
 | 
			
		||||
 | 
			
		||||
    if (ws_eapol_pdu_cb_register(interface_ptr, &eapol_pdu_recv_cb_data) < 0) {
 | 
			
		||||
        ns_dyn_mem_free(eapol_relay);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,6 +68,24 @@ int ws_management_network_name_validate(
 | 
			
		|||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ws_management_phy_mode_id_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t phy_mode_id)
 | 
			
		||||
{
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
    (void)phy_mode_id;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ws_management_channel_plan_id_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t channel_plan_id)
 | 
			
		||||
{
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
    (void)channel_plan_id;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ws_management_regulatory_domain_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t regulatory_domain,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -537,7 +537,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t *
 | 
			
		|||
                ws_llc_mpx_eapol_send(base, message);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (neighbor_info.ws_neighbor && neighbor_info.neighbor && neighbor_info.neighbor->link_lifetime < WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) {
 | 
			
		||||
            if (neighbor_info.ws_neighbor && neighbor_info.neighbor && neighbor_info.neighbor->link_lifetime <= WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME) {
 | 
			
		||||
                //Remove temp neighbour
 | 
			
		||||
                tr_debug("Remove Temp Entry by TX confirm");
 | 
			
		||||
                mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_info.neighbor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,6 +156,74 @@ int ws_management_network_name_validate(
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ws_management_phy_mode_id_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t phy_mode_id)
 | 
			
		||||
{
 | 
			
		||||
    protocol_interface_info_entry_t *cur;
 | 
			
		||||
 | 
			
		||||
    cur = protocol_stack_interface_info_get_by_id(interface_id);
 | 
			
		||||
    if (interface_id >= 0 && (!cur || !ws_info(cur))) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_phy_cfg_t cfg;
 | 
			
		||||
    ws_phy_cfg_t cfg_default;
 | 
			
		||||
    if (ws_cfg_phy_get(&cfg, NULL) < 0) {
 | 
			
		||||
        return -3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ws_cfg_phy_default_set(&cfg_default) < 0) {
 | 
			
		||||
        return -3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (phy_mode_id != 255) {
 | 
			
		||||
        cfg.phy_mode_id = phy_mode_id;
 | 
			
		||||
    } else {
 | 
			
		||||
        cfg.phy_mode_id = cfg_default.phy_mode_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) {
 | 
			
		||||
        return -4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ws_management_channel_plan_id_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t channel_plan_id)
 | 
			
		||||
{
 | 
			
		||||
    protocol_interface_info_entry_t *cur;
 | 
			
		||||
 | 
			
		||||
    cur = protocol_stack_interface_info_get_by_id(interface_id);
 | 
			
		||||
    if (interface_id >= 0 && (!cur || !ws_info(cur))) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_phy_cfg_t cfg;
 | 
			
		||||
    ws_phy_cfg_t cfg_default;
 | 
			
		||||
    if (ws_cfg_phy_get(&cfg, NULL) < 0) {
 | 
			
		||||
        return -3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ws_cfg_phy_default_set(&cfg_default) < 0) {
 | 
			
		||||
        return -3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (channel_plan_id != 255) {
 | 
			
		||||
        cfg.channel_plan_id = channel_plan_id;
 | 
			
		||||
    } else {
 | 
			
		||||
        cfg.channel_plan_id = cfg_default.channel_plan_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) {
 | 
			
		||||
        return -4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ws_management_regulatory_domain_set(
 | 
			
		||||
    int8_t interface_id,
 | 
			
		||||
    uint8_t regulatory_domain,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -254,7 +254,7 @@ void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *
 | 
			
		|||
    } else {
 | 
			
		||||
 | 
			
		||||
        if (ws_us->channel_plan == 0) {
 | 
			
		||||
            ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_common_channel_number_calc(ws_us->plan.zero.regulator_domain, ws_us->plan.zero.operation_class);
 | 
			
		||||
            ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_common_channel_number_calc(ws_us->plan.zero.regulator_domain, ws_us->plan.zero.operation_class, own_shedule->channel_plan_id);
 | 
			
		||||
        } else if (ws_us->channel_plan == 1) {
 | 
			
		||||
            ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_us->plan.one.number_of_channel;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -262,16 +262,16 @@ void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *
 | 
			
		|||
 | 
			
		||||
        //Handle excluded channel and generate activate channel list
 | 
			
		||||
        if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) {
 | 
			
		||||
            ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class);
 | 
			
		||||
            ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id);
 | 
			
		||||
            ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
 | 
			
		||||
            ws_neighbour_excluded_mask_by_range(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.range, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
 | 
			
		||||
        } else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) {
 | 
			
		||||
            ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class);
 | 
			
		||||
            ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id);
 | 
			
		||||
            ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
 | 
			
		||||
            ws_neighbour_excluded_mask_by_mask(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
 | 
			
		||||
        } else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_NONE) {
 | 
			
		||||
            if (ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels != ws_neighbor->fhss_data.uc_channel_list.channel_count) {
 | 
			
		||||
                ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class);
 | 
			
		||||
                ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id);
 | 
			
		||||
                ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -186,6 +186,7 @@ static int8_t ws_pae_key_storage_allocate(const void *instance, uint16_t key_sto
 | 
			
		|||
    if (new_storage_array == NULL) {
 | 
			
		||||
        key_storage_array->storage_array_handle = ns_dyn_mem_alloc(key_storage_size);
 | 
			
		||||
        if (!key_storage_array->storage_array_handle) {
 | 
			
		||||
            ns_dyn_mem_free(key_storage_array);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        key_storage_array->allocated = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -269,6 +269,8 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
 | 
			
		|||
 | 
			
		||||
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid)
 | 
			
		||||
{
 | 
			
		||||
    (void) br_iid;
 | 
			
		||||
 | 
			
		||||
    pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
 | 
			
		||||
    if (!pae_supp) {
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -276,24 +278,6 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr,
 | 
			
		|||
 | 
			
		||||
    tr_info("NW key valid indication");
 | 
			
		||||
 | 
			
		||||
    // Store border router EUI-64 received on bootstrap complete
 | 
			
		||||
    memcpy(pae_supp->comp_br_eui_64, br_iid, 8);
 | 
			
		||||
    pae_supp->comp_br_eui_64[0] ^= 0x02;
 | 
			
		||||
    pae_supp->comp_br_eui_64_set = true;
 | 
			
		||||
 | 
			
		||||
    // Get the EUI-64 used on 4WH handshake PTK generation
 | 
			
		||||
    uint8_t *ptk_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
 | 
			
		||||
 | 
			
		||||
    /* If border router EUI-64 received on bootstrap complete does not match to
 | 
			
		||||
       EUI-64 stored with keys, delete keys */
 | 
			
		||||
    if (!ptk_eui_64 || memcmp(ptk_eui_64, pae_supp->comp_br_eui_64, 8) != 0) {
 | 
			
		||||
        tr_warn("Delete keys: PTK EUI-64 %s does not match to BR EUI-64 %s",
 | 
			
		||||
                ptk_eui_64 ? tr_array(ptk_eui_64, 8) : "", tr_array(pae_supp->comp_br_eui_64, 8));
 | 
			
		||||
        sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
 | 
			
		||||
        sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
 | 
			
		||||
        sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Stored keys are valid
 | 
			
		||||
    pae_supp->nw_keys_used_cnt = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -357,6 +357,7 @@ static void icmpv6_na_wisun_aro_handler(protocol_interface_info_entry_t *cur_int
 | 
			
		|||
 | 
			
		||||
    (void)life_time;
 | 
			
		||||
    if (nd_status != ARO_SUCCESS) {
 | 
			
		||||
        ws_common_black_list_neighbour(src_addr, nd_status);
 | 
			
		||||
        ws_common_aro_failure(cur_interface, src_addr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1110,6 +1111,7 @@ buffer_t *icmpv6_up(buffer_t *buf)
 | 
			
		|||
                || (buf->options.type == ICMPV6_TYPE_INFO_RPL_CONTROL
 | 
			
		||||
                    && (buf->options.code != ICMPV6_CODE_RPL_DIO
 | 
			
		||||
                        && buf->options.code != ICMPV6_CODE_RPL_DIS))) {
 | 
			
		||||
            tr_warn("Drop: ICMP EP unsecured packet");
 | 
			
		||||
            goto drop;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1446,7 +1448,7 @@ static void icmpv6_aro_cb(buffer_t *buf, uint8_t status)
 | 
			
		|||
        ll_address[8] ^= 2;
 | 
			
		||||
    }
 | 
			
		||||
    if (rpl_control_address_register_done(buf->interface, ll_address, status)) {
 | 
			
		||||
        // When RPL returns true neighbor should be blacklisted
 | 
			
		||||
        // When RPL returns true neighbor should be deleted
 | 
			
		||||
        ws_common_aro_failure(buf->interface, ll_address);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1526,7 +1528,11 @@ buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t ta
 | 
			
		|||
        /* If ARO Success sending is omitted, MAC ACK is used instead */
 | 
			
		||||
        /* Setting callback for receiving ACK from adaptation layer */
 | 
			
		||||
        if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success) {
 | 
			
		||||
            buf->ack_receive_cb = icmpv6_aro_cb;
 | 
			
		||||
            if (aro->lifetime > 1) {
 | 
			
		||||
                buf->ack_receive_cb = icmpv6_aro_cb;
 | 
			
		||||
            } else {
 | 
			
		||||
                buf->ack_receive_cb = ack_receive_cb;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (unicast && (!aro && cur->ipv6_neighbour_cache.omit_na)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1761,6 +1767,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
 | 
			
		|||
            tr_debug("Neighbour removed for negative response send");
 | 
			
		||||
            return buffer_free(buf);
 | 
			
		||||
        }
 | 
			
		||||
        buf->options.traffic_class = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
        buf->ack_receive_cb = ack_remove_neighbour_cb;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1416,6 +1416,7 @@ buffer_t *ipv6_forwarding_up(buffer_t *buf)
 | 
			
		|||
#endif
 | 
			
		||||
            default: {
 | 
			
		||||
                if (buf->options.ll_security_bypass_rx) {
 | 
			
		||||
                    tr_warn("Drop: unsecured by BAD Next header %u", *nh_ptr);
 | 
			
		||||
                    goto bad_nh;
 | 
			
		||||
                }
 | 
			
		||||
                buffer_socket_set(buf, socket_lookup_ipv6(*nh_ptr, &buf->dst_sa, &buf->src_sa, true));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -180,7 +180,9 @@ typedef enum {
 | 
			
		|||
typedef enum {
 | 
			
		||||
    QOS_NORMAL = 0,
 | 
			
		||||
    QOS_HIGH = 1,
 | 
			
		||||
    QOS_MAC_BEACON = 2
 | 
			
		||||
    QOS_NETWORK_CTRL = 2,
 | 
			
		||||
    QOS_EXPEDITE_FORWARD = 3,
 | 
			
		||||
    QOS_MAC_BEACON = 4
 | 
			
		||||
} buffer_priority_t;
 | 
			
		||||
 | 
			
		||||
#define B_TO_MAC_MLME_MASK (B_DIR_MASK + B_FROM_MASK + B_TO_MASK )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@
 | 
			
		|||
#include "ipv6_stack/ipv6_routing_table.h"
 | 
			
		||||
#include "NWK_INTERFACE/Include/protocol.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_pae_controller.h"
 | 
			
		||||
#include "6LoWPAN/lowpan_adaptation_interface.h"
 | 
			
		||||
#include "NWK_INTERFACE/Include/protocol.h"
 | 
			
		||||
 | 
			
		||||
#define TRACE_GROUP "mntr"
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +74,8 @@ typedef void (ns_maintenance_gc_cb)(bool full_gc);
 | 
			
		|||
 */
 | 
			
		||||
static ns_maintenance_gc_cb *ns_maintenance_gc_functions[] = {
 | 
			
		||||
    ipv6_destination_cache_forced_gc,
 | 
			
		||||
    ws_pae_controller_forced_gc
 | 
			
		||||
    ws_pae_controller_forced_gc,
 | 
			
		||||
    lowpan_adaptation_free_heap
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ns_monitor_heap_gc(bool full_gc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
struct cca_structure_s;
 | 
			
		||||
struct buffer;
 | 
			
		||||
struct mac_pre_build_frame;
 | 
			
		||||
struct mac_pre_parsed_frame_s;
 | 
			
		||||
struct mlme_key_descriptor_s;
 | 
			
		||||
struct arm_device_driver_list;
 | 
			
		||||
struct fhss_api;
 | 
			
		||||
| 
						 | 
				
			
			@ -204,6 +205,7 @@ typedef struct protocol_interface_rf_mac_setup {
 | 
			
		|||
    bool macBroadcastDisabled: 1;
 | 
			
		||||
    bool scan_active: 1;
 | 
			
		||||
    bool rf_csma_extension_supported: 1;
 | 
			
		||||
    bool rf_pd_ack_buffer_is_in_use: 1;
 | 
			
		||||
    uint16_t mac_short_address;
 | 
			
		||||
    uint16_t pan_id;
 | 
			
		||||
    uint8_t mac64[8];
 | 
			
		||||
| 
						 | 
				
			
			@ -233,7 +235,9 @@ typedef struct protocol_interface_rf_mac_setup {
 | 
			
		|||
    struct mac_pre_build_frame *pd_data_request_queue_to_go;
 | 
			
		||||
    struct mac_pre_build_frame *pd_data_request_bc_queue_to_go;
 | 
			
		||||
    struct mac_pre_build_frame *active_pd_data_request;
 | 
			
		||||
    struct mac_pre_parsed_frame_s *pd_rx_ack_buffer;
 | 
			
		||||
    /* MAC Beacon info */
 | 
			
		||||
    uint16_t allocated_ack_buffer_length;
 | 
			
		||||
    uint16_t max_beacon_payload_length;
 | 
			
		||||
    uint8_t *mac_beacon_payload;
 | 
			
		||||
    uint8_t mac_beacon_payload_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -253,6 +257,7 @@ typedef struct protocol_interface_rf_mac_setup {
 | 
			
		|||
    struct mac_pre_build_frame enhanced_ack_buffer;
 | 
			
		||||
    uint32_t enhanced_ack_handler_timestamp;
 | 
			
		||||
    arm_event_t mac_mcps_timer_event;
 | 
			
		||||
    arm_event_storage_t mac_ack_event;
 | 
			
		||||
    uint16_t indirect_pending_bytes;
 | 
			
		||||
    arm_nwk_mlme_event_type_e mac_mlme_event;
 | 
			
		||||
    mac_event_t timer_mac_event;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,7 @@
 | 
			
		|||
#include "mac_mcps.h"
 | 
			
		||||
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
 | 
			
		||||
#include "MAC/IEEE802_15_4/mac_header_helper_functions.h"
 | 
			
		||||
#include "MAC/rf_driver_storage.h"
 | 
			
		||||
 | 
			
		||||
#define TRACE_GROUP "mFil"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +292,7 @@ int_fast8_t mac_filter_add_long(int8_t interface_id, uint8_t mac64[8], int16_t l
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, mac_pre_parsed_frame_t *mac_frame)
 | 
			
		||||
int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, struct mac_fcf_sequence_s *fcf, struct arm_pd_sap_generic_ind_s *mac_frame)
 | 
			
		||||
{
 | 
			
		||||
    filter_instance_t *this = filter_instance_find(interface_id);
 | 
			
		||||
    filter_t *filter_ptr = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -300,25 +301,24 @@ int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, mac_pre_parsed_f
 | 
			
		|||
    int16_t dbm_m;
 | 
			
		||||
    int16_t dbm_add;
 | 
			
		||||
 | 
			
		||||
    if (!this || !mac_frame) {
 | 
			
		||||
    if (!this) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!this->enabled) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    tr_debug_extra("mac_filter_modify_link_quality lqi %d dbm %d", mac_frame->link_quality, mac_frame->dbm);
 | 
			
		||||
 | 
			
		||||
    tr_debug_extra("mac_filter_modify_link_quality lqi %d dbm %d", mac_frame->LQI, mac_frame->dbm);
 | 
			
		||||
 | 
			
		||||
    if (mac_frame->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) {
 | 
			
		||||
    if (fcf->SrcAddrMode == MAC_ADDR_MODE_NONE) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    uint8_t srcAddress[8];
 | 
			
		||||
    mac_header_get_src_address(&mac_frame->fcf_dsn, mac_header_message_start_pointer(mac_frame), srcAddress);
 | 
			
		||||
    mac_header_get_src_address(fcf, mac_frame->data_ptr, srcAddress);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Find filter for specific address
 | 
			
		||||
    if (mac_frame->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_16_BIT) {
 | 
			
		||||
    if (fcf->SrcAddrMode == MAC_ADDR_MODE_16_BIT) {
 | 
			
		||||
        uint16_t mac16 = common_read_16_bit(srcAddress);
 | 
			
		||||
        filter_ptr = filter_find_short(this, mac16);
 | 
			
		||||
        if (!filter_ptr && this->resolve_long_cb) {
 | 
			
		||||
| 
						 | 
				
			
			@ -354,14 +354,14 @@ int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, mac_pre_parsed_f
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    //calculate
 | 
			
		||||
    int16_t lqi = ((mac_frame->LQI * lqi_m) >> 8) + lqi_add;
 | 
			
		||||
    int16_t lqi = ((mac_frame->link_quality * lqi_m) >> 8) + lqi_add;
 | 
			
		||||
    // Saturate
 | 
			
		||||
    if (lqi > 255) {
 | 
			
		||||
        mac_frame->LQI = 255;
 | 
			
		||||
        mac_frame->link_quality = 255;
 | 
			
		||||
    } else  if (lqi < 0) {
 | 
			
		||||
        mac_frame->LQI = 0;
 | 
			
		||||
        mac_frame->link_quality = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        mac_frame->LQI = lqi;
 | 
			
		||||
        mac_frame->link_quality = lqi;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //calculate
 | 
			
		||||
| 
						 | 
				
			
			@ -375,14 +375,14 @@ int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, mac_pre_parsed_f
 | 
			
		|||
        mac_frame->dbm = dbm;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tr_debug_extra("mac_filter_modify_link_quality result lqi %d dbm %d", mac_frame->LQI, mac_frame->dbm);
 | 
			
		||||
    tr_debug_extra("mac_filter_modify_link_quality result lqi %d dbm %d", mac_frame->link_quality, mac_frame->dbm);
 | 
			
		||||
    // If quality goes below treshold packet is dropped
 | 
			
		||||
    if ((dbm_m != 0x100 || dbm_add != 0) && (mac_frame->dbm < MAC_FILTER_SIGNAL_FLOOR)) {
 | 
			
		||||
        tr_debug_extra("Filter dropped packet signal too low");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((lqi_m != 0x100 || lqi_add != 0) && (mac_frame->LQI < 1)) {
 | 
			
		||||
    if ((lqi_m != 0x100 || lqi_add != 0) && (mac_frame->link_quality < 1)) {
 | 
			
		||||
        tr_debug_extra("Filter dropped packet LQI < 1");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,8 @@
 | 
			
		|||
#ifndef MAC_FILTER_H_
 | 
			
		||||
#define MAC_FILTER_H_
 | 
			
		||||
 | 
			
		||||
struct mac_pre_parsed_frame_s;
 | 
			
		||||
struct mac_fcf_sequence_s;
 | 
			
		||||
struct arm_pd_sap_generic_ind_s;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Modify the link quality values.
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +42,6 @@ struct mac_pre_parsed_frame_s;
 | 
			
		|||
 * return >0 Packet is ignored.
 | 
			
		||||
 * return 0 Packet is not dropped.
 | 
			
		||||
 */
 | 
			
		||||
int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, struct mac_pre_parsed_frame_s *mac_frame);
 | 
			
		||||
int_fast8_t mac_filter_modify_link_quality(int8_t interface_id, struct mac_fcf_sequence_s *fcf, struct arm_pd_sap_generic_ind_s *mac_frame);
 | 
			
		||||
 | 
			
		||||
#endif /* MAC_FILTER_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2372,6 +2372,18 @@ static mac_pre_build_frame_t *mcps_sap_pd_req_queue_read(protocol_interface_rf_m
 | 
			
		|||
 | 
			
		||||
void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    if (!buf) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (buf->mac_class_ptr && buf->fcf_dsn.frametype == FC_ACK_FRAME) {
 | 
			
		||||
        struct protocol_interface_rf_mac_setup *rf_mac_setup = buf->mac_class_ptr;
 | 
			
		||||
        if (rf_mac_setup->rf_pd_ack_buffer_is_in_use) {
 | 
			
		||||
            rf_mac_setup->rf_pd_ack_buffer_is_in_use = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_dyn_mem_free(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2388,6 +2400,37 @@ mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data
 | 
			
		|||
    return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_ack_buffer_get(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t frame_length)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    if (rf_ptr->rf_pd_ack_buffer_is_in_use) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
        tr_debug("mac ACK buffer get fail: already active");
 | 
			
		||||
#endif
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (frame_length > rf_ptr->allocated_ack_buffer_length) {
 | 
			
		||||
        //Free Current
 | 
			
		||||
        if (rf_ptr->pd_rx_ack_buffer) {
 | 
			
		||||
            ns_dyn_mem_free(rf_ptr->pd_rx_ack_buffer);
 | 
			
		||||
            rf_ptr->allocated_ack_buffer_length = 0;
 | 
			
		||||
        }
 | 
			
		||||
        rf_ptr->pd_rx_ack_buffer = ns_dyn_mem_alloc(sizeof(mac_pre_parsed_frame_t) + frame_length);
 | 
			
		||||
        if (!rf_ptr->pd_rx_ack_buffer) {
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        rf_ptr->allocated_ack_buffer_length = frame_length;
 | 
			
		||||
    }
 | 
			
		||||
    memset(rf_ptr->pd_rx_ack_buffer, 0, sizeof(mac_pre_parsed_frame_t) + rf_ptr->allocated_ack_buffer_length);
 | 
			
		||||
    rf_ptr->pd_rx_ack_buffer->frameLength = frame_length;
 | 
			
		||||
    memcpy(mac_header_message_start_pointer(rf_ptr->pd_rx_ack_buffer), data_ptr, frame_length);
 | 
			
		||||
    //Mark active ACK buffer state
 | 
			
		||||
    rf_ptr->rf_pd_ack_buffer_is_in_use = true;
 | 
			
		||||
    return rf_ptr->pd_rx_ack_buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void mac_set_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type)
 | 
			
		||||
{
 | 
			
		||||
    rf_mac_setup->active_mac_events |= (1 << event_type);
 | 
			
		||||
| 
						 | 
				
			
			@ -2458,21 +2501,36 @@ int8_t mcps_sap_pd_confirm_failure(void *mac_ptr)
 | 
			
		|||
    return eventOS_event_send(&event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mcps_sap_pd_ack(void *ack_ptr)
 | 
			
		||||
int8_t mcps_sap_pd_ack(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_parsed_frame_t *buffer)
 | 
			
		||||
{
 | 
			
		||||
    if (mac_tasklet_event_handler < 0  || !ack_ptr) {
 | 
			
		||||
        return;
 | 
			
		||||
    if (mac_tasklet_event_handler < 0  || !buffer) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (buffer->fcf_dsn.frametype == FC_ACK_FRAME) {
 | 
			
		||||
        arm_event_storage_t *event = &rf_ptr->mac_ack_event;
 | 
			
		||||
        event->data.data_ptr = buffer;
 | 
			
		||||
        event->data.event_data = 0;
 | 
			
		||||
        event->data.event_id = 0;
 | 
			
		||||
        event->data.event_type = MCPS_SAP_DATA_ACK_CNF_EVENT;
 | 
			
		||||
        event->data.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
 | 
			
		||||
        event->data.sender = 0;
 | 
			
		||||
        event->data.receiver = mac_tasklet_event_handler;
 | 
			
		||||
        eventOS_event_send_user_allocated(event);
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    arm_event_s event = {
 | 
			
		||||
        .receiver = mac_tasklet_event_handler,
 | 
			
		||||
        .sender = 0,
 | 
			
		||||
        .event_id = 0,
 | 
			
		||||
        .data_ptr = ack_ptr,
 | 
			
		||||
        .data_ptr = buffer,
 | 
			
		||||
        .event_type = MCPS_SAP_DATA_ACK_CNF_EVENT,
 | 
			
		||||
        .priority = ARM_LIB_HIGH_PRIORITY_EVENT,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    eventOS_event_send(&event);
 | 
			
		||||
    return eventOS_event_send(&event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mcps_sap_trig_tx(void *mac_ptr)
 | 
			
		||||
| 
						 | 
				
			
			@ -2566,6 +2624,17 @@ void mac_mcps_buffer_queue_free(protocol_interface_rf_mac_setup_s *rf_mac_setup)
 | 
			
		|||
            mcps_sap_prebuild_frame_buffer_free(buffer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rf_mac_setup->pd_rx_ack_buffer) {
 | 
			
		||||
        if (rf_mac_setup->rf_pd_ack_buffer_is_in_use) {
 | 
			
		||||
            eventOS_cancel(&rf_mac_setup->mac_ack_event);
 | 
			
		||||
            rf_mac_setup->rf_pd_ack_buffer_is_in_use = false;
 | 
			
		||||
        }
 | 
			
		||||
        ns_dyn_mem_free(rf_mac_setup->pd_rx_ack_buffer);
 | 
			
		||||
        rf_mac_setup->pd_rx_ack_buffer = NULL;
 | 
			
		||||
        rf_mac_setup->allocated_ack_buffer_length = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * Function return list start pointer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ struct mcps_purge_s;
 | 
			
		|||
struct mcps_data_req_ie_list;
 | 
			
		||||
struct channel_list_s;
 | 
			
		||||
struct mcps_enhanced_frame_response_s;
 | 
			
		||||
struct mac_pre_parsed_frame_s;
 | 
			
		||||
 | 
			
		||||
/** Address types */
 | 
			
		||||
typedef enum {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +101,8 @@ void mcps_sap_pd_req_queue_write(struct protocol_interface_rf_mac_setup *rf_mac_
 | 
			
		|||
 */
 | 
			
		||||
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length);
 | 
			
		||||
 | 
			
		||||
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_ack_buffer_get(struct protocol_interface_rf_mac_setup *rf_ptr, const uint8_t *data_ptr, uint16_t frame_length);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Forward Buffer for MAC MCPS SAP layer event handler
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +115,7 @@ int8_t mcps_sap_pd_confirm(void *mac_ptr);
 | 
			
		|||
 | 
			
		||||
int8_t mcps_sap_pd_confirm_failure(void *mac_ptr);
 | 
			
		||||
 | 
			
		||||
void mcps_sap_pd_ack(void *ack_ptr);
 | 
			
		||||
int8_t mcps_sap_pd_ack(struct protocol_interface_rf_mac_setup *rf_ptr, struct mac_pre_parsed_frame_s *buffer);
 | 
			
		||||
 | 
			
		||||
int8_t mac_virtual_sap_data_cb(void *identifier, struct arm_phy_sap_msg_s *message);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -828,6 +828,9 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m
 | 
			
		|||
            tr_info("Number of channels: %u", config_params->number_of_channels);
 | 
			
		||||
            tr_info("Modulation: %u", config_params->modulation);
 | 
			
		||||
            tr_info("Modulation index: %u", config_params->modulation_index);
 | 
			
		||||
            tr_info("FEC: %u", config_params->fec);
 | 
			
		||||
            tr_info("OFDM MCS: %u", config_params->ofdm_mcs);
 | 
			
		||||
            tr_info("OFDM option: %u", config_params->ofdm_option);
 | 
			
		||||
            return 0;
 | 
			
		||||
        default:
 | 
			
		||||
            return mac_mlme_handle_set_values(rf_mac_setup, set_req);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -480,6 +480,8 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
 | 
			
		|||
                                                               rf_ptr->dev_driver->phy_driver->phy_tail_length, active_buf->tx_time);
 | 
			
		||||
            // When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer
 | 
			
		||||
            if (tx_handle_retval == -1) {
 | 
			
		||||
                // RX channel could have changed during CSMA-CA, must update using TX done callback
 | 
			
		||||
                rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, rf_ptr->active_pd_data_request->msduHandle);
 | 
			
		||||
                mac_sap_cca_fail_cb(rf_ptr, 0xffff);
 | 
			
		||||
                return PHY_TX_NOT_ALLOWED;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -631,14 +633,19 @@ VALIDATE_TX_TIME:
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t mac_data_interface_waiting_ack(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read)
 | 
			
		||||
{
 | 
			
		||||
    if (!rf_ptr->macRfRadioTxActive || !rf_ptr->active_pd_data_request || rf_ptr->active_pd_data_request->fcf_dsn.DSN != fcf_read->DSN) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_parsed_frame_t *buf)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    if (!rf_ptr->macRfRadioTxActive || !rf_ptr->active_pd_data_request || rf_ptr->active_pd_data_request->fcf_dsn.DSN != buf->fcf_dsn.DSN) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    timer_mac_stop(rf_ptr);
 | 
			
		||||
    if (buf->fcf_dsn.framePending) {
 | 
			
		||||
        rf_ptr->mac_tx_result = MAC_TX_DONE_PENDING;
 | 
			
		||||
| 
						 | 
				
			
			@ -647,7 +654,9 @@ static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_set
 | 
			
		|||
    }
 | 
			
		||||
    rf_ptr->macRfRadioTxActive = false;
 | 
			
		||||
    rf_ptr->macTxProcessActive = false;
 | 
			
		||||
    mcps_sap_pd_ack(buf);
 | 
			
		||||
    if (mcps_sap_pd_ack(rf_ptr, buf) != 0) {
 | 
			
		||||
        mcps_sap_pre_parsed_frame_buffer_free(buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rf_ptr->fhss_api) {
 | 
			
		||||
        rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, true, rf_ptr->active_pd_data_request->msduHandle);
 | 
			
		||||
| 
						 | 
				
			
			@ -891,22 +900,35 @@ static int8_t mac_pd_sap_generate_edfe_response(protocol_interface_rf_mac_setup_
 | 
			
		|||
static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
 | 
			
		||||
{
 | 
			
		||||
    // Unless receiving Ack, check that system has enough space to handle the new packet
 | 
			
		||||
    if (fcf_read->frametype != FC_ACK_FRAME) {
 | 
			
		||||
        if (!ns_monitor_packet_allocation_allowed()) {
 | 
			
		||||
    mac_pre_parsed_frame_t *buffer = NULL;
 | 
			
		||||
    if (fcf_read->frametype != FC_ACK_FRAME || rf_ptr->macProminousMode) {
 | 
			
		||||
        if (!rf_ptr->macProminousMode && !ns_monitor_packet_allocation_allowed()) {
 | 
			
		||||
            // stack can not handle new packets for routing
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
            tr_debug("Packet ingress drop buffer allocation");
 | 
			
		||||
#endif
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
 | 
			
		||||
    if (!buffer) {
 | 
			
		||||
 | 
			
		||||
        buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
 | 
			
		||||
        if (!buffer) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
        tr_debug("macPD buffer allocate fail %u", pd_data_ind->data_len);
 | 
			
		||||
            tr_debug("macPD buffer allocate fail %u", pd_data_ind->data_len);
 | 
			
		||||
#endif
 | 
			
		||||
        return NULL;
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        //Allocate ACK buffer
 | 
			
		||||
        buffer = mcps_sap_pre_parsed_ack_buffer_get(rf_ptr, pd_data_ind->data_ptr, pd_data_ind->data_len);
 | 
			
		||||
        if (!buffer) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
            tr_debug("macPD ACK buffer allocate fail %u", pd_data_ind->data_len);
 | 
			
		||||
#endif
 | 
			
		||||
            return NULL;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Copy Pre Parsed values
 | 
			
		||||
    buffer->fcf_dsn = *fcf_read;
 | 
			
		||||
    buffer->timestamp = mac_pd_sap_get_phy_rx_time(rf_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1012,11 +1034,20 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
 | 
			
		|||
        mac_fcf_sequence_t fcf_read;
 | 
			
		||||
        const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr);
 | 
			
		||||
 | 
			
		||||
        buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
 | 
			
		||||
        if (buffer && mac_filter_modify_link_quality(rf_ptr->mac_interface_id, buffer) == 1) {
 | 
			
		||||
        // No need to send Ack - Check if RX channel needs to be updated
 | 
			
		||||
        if (fcf_read.ackRequested == false) {
 | 
			
		||||
            if (rf_ptr->fhss_api) {
 | 
			
		||||
                rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Modify link quality
 | 
			
		||||
        if (mac_filter_modify_link_quality(rf_ptr->mac_interface_id, &fcf_read, pd_data_ind) == 1) {
 | 
			
		||||
            goto ERROR_HANDLER;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!rf_ptr->macProminousMode) {
 | 
			
		||||
            //Pre validate things before allocate buffer
 | 
			
		||||
            if (mac_pd_sap_validate_fcf(rf_ptr, &fcf_read, pd_data_ind)) {
 | 
			
		||||
                goto ERROR_HANDLER;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,12 +1055,26 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
 | 
			
		|||
                pd_data_ind->data_len = 0; // Do not update RX drop in that case
 | 
			
		||||
                goto ERROR_HANDLER;
 | 
			
		||||
            }
 | 
			
		||||
            //Ack can be send even buffer allocate fail
 | 
			
		||||
            if (mac_pd_sap_generate_ack(rf_ptr, &fcf_read, pd_data_ind)) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
                tr_debug("Drop a Data by ignored ACK generation");
 | 
			
		||||
#endif
 | 
			
		||||
                goto ERROR_HANDLER;
 | 
			
		||||
            }
 | 
			
		||||
            if (fcf_read.frametype == FC_ACK_FRAME && mac_data_interface_waiting_ack(rf_ptr, &fcf_read)) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
                tr_debug("Drop a ACK not a proper DSN");
 | 
			
		||||
#endif
 | 
			
		||||
                goto ERROR_HANDLER;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        //Allocate Buffer
 | 
			
		||||
        buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
 | 
			
		||||
 | 
			
		||||
        if (!rf_ptr->macProminousMode) {
 | 
			
		||||
 | 
			
		||||
            if (buffer) {
 | 
			
		||||
                if (mac_pd_sap_parse_length_fields(buffer, pd_data_ind, ptr)) {
 | 
			
		||||
                    goto ERROR_HANDLER;
 | 
			
		||||
| 
						 | 
				
			
			@ -1098,7 +1143,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
 | 
			
		|||
                            //Mark session closed
 | 
			
		||||
                            rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
 | 
			
		||||
                            rf_ptr->mac_edfe_tx_active = false;
 | 
			
		||||
                            if (mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) {
 | 
			
		||||
                            if (mac_data_interface_waiting_ack(rf_ptr, &buffer->fcf_dsn) || mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) {
 | 
			
		||||
                                mcps_sap_pre_parsed_frame_buffer_free(buffer);
 | 
			
		||||
                            }
 | 
			
		||||
                            return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -406,6 +406,7 @@ static mpl_buffered_message_t *mpl_buffer_create(buffer_t *buf, mpl_domain_t *do
 | 
			
		|||
    uint16_t ip_len = buffer_data_length(buf);
 | 
			
		||||
 | 
			
		||||
    while (mpl_total_buffered + ip_len > MAX_BUFFERED_MESSAGES_SIZE) {
 | 
			
		||||
        tr_debug("MPL MAX buffered message size limit...free space");
 | 
			
		||||
        mpl_free_space();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -427,6 +428,7 @@ static mpl_buffered_message_t *mpl_buffer_create(buffer_t *buf, mpl_domain_t *do
 | 
			
		|||
 | 
			
		||||
    mpl_buffered_message_t *message = ns_dyn_mem_alloc(sizeof(mpl_buffered_message_t) + ip_len);
 | 
			
		||||
    if (!message) {
 | 
			
		||||
        tr_debug("No heap for new MPL message");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    memcpy(message->message, buffer_data_pointer(buf), ip_len);
 | 
			
		||||
| 
						 | 
				
			
			@ -475,6 +477,7 @@ static void mpl_buffer_transmit(mpl_domain_t *domain, mpl_buffered_message_t *me
 | 
			
		|||
    uint16_t ip_len = mpl_buffer_size(message);
 | 
			
		||||
    buffer_t *buf = buffer_get(ip_len);
 | 
			
		||||
    if (!buf) {
 | 
			
		||||
        tr_debug("No heap for MPL transmit");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -939,6 +942,9 @@ bool mpl_forwarder_process_message(buffer_t *buf, mpl_domain_t *domain, bool see
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    message = mpl_buffer_create(buf, domain, seed, sequence, hop_limit);
 | 
			
		||||
    if (!message) {
 | 
			
		||||
        tr_debug("MPL Buffer Craete fail");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,7 @@ struct arm_device_driver_list;
 | 
			
		|||
struct mlme_security_s;
 | 
			
		||||
struct load_balance_api;
 | 
			
		||||
struct nwk_wpan_nvm_api;
 | 
			
		||||
struct red_info_s;
 | 
			
		||||
 | 
			
		||||
#define SLEEP_MODE_REQ      0x80
 | 
			
		||||
#define SLEEP_PERIOD_ACTIVE 0x40
 | 
			
		||||
| 
						 | 
				
			
			@ -445,6 +446,7 @@ struct protocol_interface_info_entry {
 | 
			
		|||
    struct auth_info *pana_sec_info_temp;
 | 
			
		||||
    br_info_t *border_router_setup;
 | 
			
		||||
    struct load_balance_api *lb_api;
 | 
			
		||||
    struct red_info_s *random_early_detection;
 | 
			
		||||
    neigh_cache_s neigh_cache;
 | 
			
		||||
    pan_blaclist_cache_s pan_blaclist_cache;
 | 
			
		||||
    pan_coordinator_blaclist_cache_s pan_cordinator_black_list;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,7 +44,8 @@ typedef enum {
 | 
			
		|||
    STATS_BUFFER_HEADROOM_FAIL,
 | 
			
		||||
    STATS_ETX_1ST_PARENT,
 | 
			
		||||
    STATS_ETX_2ND_PARENT,
 | 
			
		||||
    STATS_AL_TX_QUEUE_SIZE
 | 
			
		||||
    STATS_AL_TX_QUEUE_SIZE,
 | 
			
		||||
    STATS_AL_TX_CONGESTION_DROP
 | 
			
		||||
 | 
			
		||||
} nwk_stats_type_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,6 +152,9 @@ void protocol_stats_update(nwk_stats_type_t type, uint16_t update_val)
 | 
			
		|||
                    nwk_stats_ptr->adapt_layer_tx_queue_peak = nwk_stats_ptr->adapt_layer_tx_queue_size;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case STATS_AL_TX_CONGESTION_DROP:
 | 
			
		||||
                nwk_stats_ptr->adapt_layer_tx_congestion_drop++;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,7 @@
 | 
			
		|||
#include "NWK_INTERFACE/Include/protocol_stats.h"
 | 
			
		||||
#include "Common_Protocols/ipv6_constants.h"
 | 
			
		||||
#include "Common_Protocols/icmpv6.h"
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
#include "ipv6_stack/protocol_ipv6.h"
 | 
			
		||||
#include "Service_Libs/etx/etx.h" /* slight ick */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1168,6 +1169,23 @@ malformed:
 | 
			
		|||
        goto invalid_parent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* RFC 6550 8.3: A DIO from a sender with lesser DAGRank that causes no
 | 
			
		||||
     * changes to the recipient's parent set, preferred parent, or Rank SHOULD
 | 
			
		||||
     * be considered consistent with respect to the Trickle timer.
 | 
			
		||||
     *
 | 
			
		||||
     * Now, if we don't run parent selection immediately, how do we know if it's
 | 
			
		||||
     * consistent or not? Compromise is to treat all lower ranked DIOs as
 | 
			
		||||
     * consistent, and reset (and hold) the consistent counter to 0 if any of
 | 
			
		||||
     * the above change. This actually seems better than the RFC 6550 rule, as
 | 
			
		||||
     * it guarantees we will transmit if those change. The rule as stated
 | 
			
		||||
     * would mean a large number of parent messages would stop us advertising
 | 
			
		||||
     * a Rank change.
 | 
			
		||||
     */
 | 
			
		||||
    if (version == rpl_instance_current_dodag_version(instance) &&
 | 
			
		||||
            (rpl_rank_compare(dodag, rank, rpl_instance_current_rank(instance)) & RPL_CMP_LESS)) {
 | 
			
		||||
        rpl_instance_consistent_rx(instance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Now we create the neighbour, if we don't already have a record */
 | 
			
		||||
    if (!neighbour) {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1207,23 +1225,6 @@ malformed:
 | 
			
		|||
        rpl_dodag_set_leaf(dodag, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* RFC 6550 8.3: A DIO from a sender with lesser DAGRank that causes no
 | 
			
		||||
     * changes to the recipient's parent set, preferred parent, or Rank SHOULD
 | 
			
		||||
     * be considered consistent with respect to the Trickle timer.
 | 
			
		||||
     *
 | 
			
		||||
     * Now, if we don't run parent selection immediately, how do we know if it's
 | 
			
		||||
     * consistent or not? Compromise is to treat all lower ranked DIOs as
 | 
			
		||||
     * consistent, and reset (and hold) the consistent counter to 0 if any of
 | 
			
		||||
     * the above change. This actually seems better than the RFC 6550 rule, as
 | 
			
		||||
     * it guarantees we will transmit if those change. The rule as stated
 | 
			
		||||
     * would mean a large number of parent messages would stop us advertising
 | 
			
		||||
     * a Rank change.
 | 
			
		||||
     */
 | 
			
		||||
    if (version == rpl_instance_current_dodag_version(instance) &&
 | 
			
		||||
            (rpl_rank_compare(dodag, rank, rpl_instance_current_rank(instance)) & RPL_CMP_LESS)) {
 | 
			
		||||
        rpl_instance_consistent_rx(instance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rpl_instance_neighbours_changed(instance, dodag);
 | 
			
		||||
 | 
			
		||||
    return buffer_free(buf);
 | 
			
		||||
| 
						 | 
				
			
			@ -1292,6 +1293,10 @@ void rpl_control_transmit(rpl_domain_t *domain, protocol_interface_info_entry_t
 | 
			
		|||
    /* Others set "0", which means use interface default */
 | 
			
		||||
    buf->options.hop_limit = addr_ipv6_scope(buf->dst_sa.address, cur) <= IPV6_SCOPE_LINK_LOCAL ? 255 : 0;
 | 
			
		||||
 | 
			
		||||
    if (code == ICMPV6_CODE_RPL_DAO || code == ICMPV6_CODE_RPL_DAO_ACK || buf->dst_sa.address[0] != 0xff) {
 | 
			
		||||
        //DAO and DAO ACK and unicast traffic with Higher priority
 | 
			
		||||
        buf->options.traffic_class = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dst == NULL && cur == NULL) {
 | 
			
		||||
        rpl_control_transmit_all_interfaces(domain, buf);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,7 @@
 | 
			
		|||
#include "Common_Protocols/icmpv6.h"
 | 
			
		||||
#include "NWK_INTERFACE/Include/protocol.h"
 | 
			
		||||
#include "ipv6_stack/ipv6_routing_table.h"
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
 | 
			
		||||
#include "net_rpl.h"
 | 
			
		||||
#include "RPL/rpl_protocol.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -884,9 +885,24 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance)
 | 
			
		|||
    instance->requested_dao_ack = need_ack;
 | 
			
		||||
    instance->dao_in_transit = true;
 | 
			
		||||
    if (instance->dao_attempt < 16) {
 | 
			
		||||
        uint32_t t = (uint32_t) rpl_policy_initial_dao_ack_wait(instance->domain, mop) << instance->dao_attempt;
 | 
			
		||||
        t = randLIB_randomise_base(t, 0x4000, 0xC000);
 | 
			
		||||
        instance->dao_retry_timer = t <= 0xffff ? t : 0xffff;
 | 
			
		||||
 | 
			
		||||
        uint32_t delay = rpl_policy_initial_dao_ack_wait(instance->domain, mop);
 | 
			
		||||
        if (delay < dodag->dio_timer_params.Imin) {
 | 
			
		||||
            //Use Imin Based on delay if it is longer than cache retry
 | 
			
		||||
            delay = dodag->dio_timer_params.Imin;
 | 
			
		||||
        }
 | 
			
		||||
        //Multiply Delay by attempt
 | 
			
		||||
        delay = delay << instance->dao_attempt;
 | 
			
		||||
 | 
			
		||||
        if (delay > 5400) {
 | 
			
		||||
            //MAX base 540 seconds (9min)
 | 
			
		||||
            delay = 5400;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 0.5 - 1.5 *t randomized base delay
 | 
			
		||||
        delay = randLIB_randomise_base(delay, 0x4000, 0xC000);
 | 
			
		||||
 | 
			
		||||
        instance->dao_retry_timer = delay;
 | 
			
		||||
    } else {
 | 
			
		||||
        instance->dao_retry_timer = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1874,6 +1890,7 @@ static bool rpl_instance_push_address_registration(protocol_interface_info_entry
 | 
			
		|||
    if (!buf) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    buf->options.traffic_class = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
    tr_info("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address));
 | 
			
		||||
    protocol_push(buf);
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -180,6 +180,7 @@ struct rpl_instance {
 | 
			
		|||
    bool requested_dao_ack: 1;                      /* If we requested an ACK (so we retry if no ACK, rather than assuming success) */
 | 
			
		||||
    bool pending_neighbour_confirmation: 1;         /* if we have not finished address registration state to parent */
 | 
			
		||||
    bool parent_was_selected: 1;
 | 
			
		||||
    bool advertised_dodag_membership_since_last_repair: 1; /* advertised dodag membership since last repair */
 | 
			
		||||
    uint8_t poison_count;
 | 
			
		||||
    uint8_t repair_dis_count;
 | 
			
		||||
    uint16_t repair_dis_timer;
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +193,7 @@ struct rpl_instance {
 | 
			
		|||
    rpl_dodag_version_t *current_dodag_version;     /* Pointer to DODAG version we are a member of (if any) */
 | 
			
		||||
    uint16_t current_rank;                          /* Current rank in current DODAG Version */
 | 
			
		||||
    uint16_t parent_selection_timer;
 | 
			
		||||
    rpl_dodag_version_t *last_advertised_dodag_version; /* Pointer to last DODAG version we advertised */
 | 
			
		||||
 | 
			
		||||
    trickle_t dio_timer;                            /* Trickle timer for DIO transmission */
 | 
			
		||||
    rpl_dao_root_transit_children_list_t root_children;
 | 
			
		||||
    rpl_dao_target_list_t dao_targets;              /* List of DAO targets */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1665,8 +1665,9 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_
 | 
			
		|||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    rpl_dodag_version_limit_greediness(dodag_version, rank);
 | 
			
		||||
 | 
			
		||||
    instance->last_advertised_dodag_version = dodag_version;
 | 
			
		||||
    if (rank != RPL_RANK_INFINITE) {
 | 
			
		||||
        instance->advertised_dodag_membership_since_last_repair = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rpl_instance_dis_timer(rpl_instance_t *instance, uint16_t seconds)
 | 
			
		||||
| 
						 | 
				
			
			@ -1715,6 +1716,7 @@ void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair)
 | 
			
		|||
        instance->repair_dis_count = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        instance->repair_dis_timer = 0;
 | 
			
		||||
        instance->advertised_dodag_membership_since_last_repair = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* When repair ends, eliminate all higher-rank neighbours (potential sub-DODAG) from table */
 | 
			
		||||
| 
						 | 
				
			
			@ -1839,8 +1841,14 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks)
 | 
			
		|||
 | 
			
		||||
    /* Delay sending first DIO if we are still potentially gathering info */
 | 
			
		||||
    /* Important to always send DIOs if we ever have sent any, so we can indicate problems to others */
 | 
			
		||||
    if (!rpl_instance_am_root(instance) && !instance->last_advertised_dodag_version && rpl_policy_parent_confirmation_requested()) {
 | 
			
		||||
        // We dont have any valid parent selected
 | 
			
		||||
    if (!rpl_instance_am_root(instance) && !instance->poison_count && !instance->advertised_dodag_membership_since_last_repair && rpl_policy_parent_confirmation_requested()) {
 | 
			
		||||
 | 
			
		||||
        // We don't have DAO target generated
 | 
			
		||||
        if (ns_list_count(&instance->dao_targets) == 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We don't have any valid parent selected
 | 
			
		||||
        if (!rpl_instance_parent_selection_ready(instance)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -652,6 +652,14 @@ static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t
 | 
			
		|||
    radius_msg_length += AVP_TYPE_NAS_IPV6_ADDRESS_LEN;
 | 
			
		||||
 | 
			
		||||
    uint8_t *radius_msg_ptr = ns_dyn_mem_temporary_alloc(radius_msg_length);
 | 
			
		||||
    if (radius_msg_ptr == NULL) {
 | 
			
		||||
        if (data->send_radius_msg != NULL) {
 | 
			
		||||
            ns_dyn_mem_free(data->send_radius_msg);
 | 
			
		||||
        }
 | 
			
		||||
        data->send_radius_msg = NULL;
 | 
			
		||||
        data->send_radius_msg_len = 0;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    uint8_t *radius_msg_start_ptr = radius_msg_ptr;
 | 
			
		||||
 | 
			
		||||
    *radius_msg_ptr++ = RADIUS_ACCESS_REQUEST;                                // code
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -416,7 +416,7 @@ static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int l
 | 
			
		|||
 | 
			
		||||
int8_t tls_sec_prot_lib_process(tls_security_t *sec)
 | 
			
		||||
{
 | 
			
		||||
    int ret = -1;
 | 
			
		||||
    int32_t ret = -1;
 | 
			
		||||
 | 
			
		||||
    while (ret != MBEDTLS_ERR_SSL_WANT_READ) {
 | 
			
		||||
        ret = mbedtls_ssl_handshake_step(&sec->ssl);
 | 
			
		||||
| 
						 | 
				
			
			@ -428,6 +428,7 @@ int8_t tls_sec_prot_lib_process(tls_security_t *sec)
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
        if (ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)) {
 | 
			
		||||
            tr_error("TLS error: %" PRId32, ret);
 | 
			
		||||
            return TLS_SEC_PROT_LIB_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@ target_include_directories(mbed-nanostack-sal_stack
 | 
			
		|||
        ./nd_proxy
 | 
			
		||||
        ./nist_aes_kw
 | 
			
		||||
        ./pan_blacklist
 | 
			
		||||
        ./random_early_detection
 | 
			
		||||
        ./utils
 | 
			
		||||
        ./whiteboard
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +94,8 @@ target_sources(mbed-nanostack-sal_stack
 | 
			
		|||
        nist_aes_kw/nist_aes_kw.c
 | 
			
		||||
 | 
			
		||||
        pan_blacklist/pan_blacklist.c
 | 
			
		||||
        
 | 
			
		||||
        random_early_detection/random_early_detection.c
 | 
			
		||||
 | 
			
		||||
        utils/isqrt.c
 | 
			
		||||
        utils/ns_conf.c
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ struct fhss_structure {
 | 
			
		|||
    uint8_t active_fhss_events;
 | 
			
		||||
    uint16_t number_of_channels;
 | 
			
		||||
    uint16_t number_of_uc_channels;
 | 
			
		||||
    uint16_t number_of_bc_channels;
 | 
			
		||||
    uint16_t optimal_packet_length;
 | 
			
		||||
    fhss_states fhss_state;
 | 
			
		||||
    uint32_t fhss_timeout;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure)
 | 
			
		|||
    if (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval == 0 || fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval == 0) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS;
 | 
			
		||||
    uint32_t txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS_MAX;
 | 
			
		||||
    if (fhss_structure->callbacks.read_datarate) {
 | 
			
		||||
        /* Calculate minimum TX slot length which can fit optimal packet length twice.
 | 
			
		||||
         * Twice, because 0, 1, 4, 5... hop starts transmission at the beginning of TX slot and 2, 3, 6, 7... hop at the middle of TX slot
 | 
			
		||||
| 
						 | 
				
			
			@ -217,9 +217,14 @@ void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure)
 | 
			
		|||
        if (datarate) {
 | 
			
		||||
            txrx_slot_length_ms_tmp = ((fhss_structure->optimal_packet_length * 2) * (8000000 / datarate)) / 1000;
 | 
			
		||||
            // Do not allow using too high TX slot length.
 | 
			
		||||
            if (txrx_slot_length_ms_tmp > WS_TXRX_SLOT_LEN_MS) {
 | 
			
		||||
                tr_debug("TX slot length setting too high %"PRIu32"ms, using %"PRIu32"ms", txrx_slot_length_ms_tmp, (uint32_t)WS_TXRX_SLOT_LEN_MS);
 | 
			
		||||
                txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS;
 | 
			
		||||
            if (txrx_slot_length_ms_tmp > WS_TXRX_SLOT_LEN_MS_MAX) {
 | 
			
		||||
                tr_debug("TX slot length setting too high %"PRIu32"ms, using %"PRIu32"ms", txrx_slot_length_ms_tmp, (uint32_t)WS_TXRX_SLOT_LEN_MS_MAX);
 | 
			
		||||
                txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS_MAX;
 | 
			
		||||
            }
 | 
			
		||||
            // Do not allow using too low TX slot length.
 | 
			
		||||
            if (txrx_slot_length_ms_tmp < WS_TXRX_SLOT_LEN_MS_MIN) {
 | 
			
		||||
                tr_debug("TX slot length setting too low %"PRIu32"ms, using %"PRIu32"ms", txrx_slot_length_ms_tmp, (uint32_t)WS_TXRX_SLOT_LEN_MS_MIN);
 | 
			
		||||
                txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS_MIN;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -241,14 +246,14 @@ static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure)
 | 
			
		|||
    int32_t next_channel = fhss_structure->ws->fhss_configuration.broadcast_fixed_channel;
 | 
			
		||||
 | 
			
		||||
    if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) {
 | 
			
		||||
        next_channel = tr51_get_bc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels, NULL);
 | 
			
		||||
        next_channel = tr51_get_bc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_bc_channels, NULL);
 | 
			
		||||
        next_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.channel_mask, next_channel, fhss_structure->number_of_channels);
 | 
			
		||||
        if (++fhss_structure->ws->bc_slot == fhss_structure->number_of_channels) {
 | 
			
		||||
        if (++fhss_structure->ws->bc_slot == fhss_structure->number_of_bc_channels) {
 | 
			
		||||
            fhss_structure->ws->bc_slot = 0;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_DH1CF) {
 | 
			
		||||
        fhss_structure->ws->bc_slot++;
 | 
			
		||||
        next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
 | 
			
		||||
        next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_bc_channels);
 | 
			
		||||
        next_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.channel_mask, next_channel, fhss_structure->number_of_channels);
 | 
			
		||||
    } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_VENDOR_DEF_CF) {
 | 
			
		||||
        if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) {
 | 
			
		||||
| 
						 | 
				
			
			@ -338,7 +343,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) {
 | 
			
		||||
        fhss_structure->ws->bc_slot %= fhss_structure->number_of_channels;
 | 
			
		||||
        fhss_structure->ws->bc_slot %= fhss_structure->number_of_bc_channels;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fhss_structure->ws->is_on_bc_channel == false) {
 | 
			
		||||
| 
						 | 
				
			
			@ -604,9 +609,14 @@ static int fhss_ws_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_a
 | 
			
		|||
    if (!fhss_structure) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (is_broadcast_addr) {
 | 
			
		||||
    // Allow broadcast destination on broadcast channel
 | 
			
		||||
    if (is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    // Do not allow broadcast destination on unicast channel
 | 
			
		||||
    if (is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == false)) {
 | 
			
		||||
        return -3;
 | 
			
		||||
    }
 | 
			
		||||
    // Do not allow unicast destination on broadcast channel
 | 
			
		||||
    if (!is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -919,7 +929,7 @@ static uint32_t fhss_ws_get_retry_period_callback(const fhss_api_t *api, uint8_t
 | 
			
		|||
    uint32_t cur_time_us = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api);
 | 
			
		||||
    uint32_t tx_trig_offset_us = (txrx_slot_length_us / 2) * calc_own_tx_trig_slot(fhss_structure->own_hop);
 | 
			
		||||
 | 
			
		||||
    uint32_t next_tx_trig_slot_start_us = unicast_start_us + (txrx_slot_length_us * !fhss_ws_check_tx_allowed(fhss_structure)) + tx_trig_offset_us;
 | 
			
		||||
    uint32_t next_tx_trig_slot_start_us = unicast_start_us + (txrx_slot_length_us * (fhss_structure->own_hop & 1)) + tx_trig_offset_us;
 | 
			
		||||
    uint32_t next_tx_trig_slot_end_us = next_tx_trig_slot_start_us + (txrx_slot_length_us / 2);
 | 
			
		||||
    while ((next_tx_trig_slot_start_us < cur_time_us) || ((next_tx_trig_slot_start_us - cur_time_us) > (uint32_t) MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval))) {
 | 
			
		||||
        if (cur_time_us < next_tx_trig_slot_end_us) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1076,13 +1086,13 @@ int fhss_ws_remove_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[
 | 
			
		|||
 | 
			
		||||
int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_configuration_t *fhss_configuration)
 | 
			
		||||
{
 | 
			
		||||
    int channel_count = channel_list_count_channels(fhss_configuration->channel_mask);
 | 
			
		||||
    int channel_count_bc = channel_list_count_channels(fhss_configuration->channel_mask);
 | 
			
		||||
    int channel_count_uc = channel_list_count_channels(fhss_configuration->unicast_channel_mask);
 | 
			
		||||
    if (channel_count <= 0) {
 | 
			
		||||
    if (channel_count_bc <= 0 || fhss_configuration->channel_mask_size == 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fhss_structure->number_of_channels < channel_count ||
 | 
			
		||||
    if (fhss_structure->number_of_bc_channels < channel_count_bc ||
 | 
			
		||||
            (channel_count_uc && fhss_structure->number_of_uc_channels < channel_count_uc)) {
 | 
			
		||||
        // Channel amount changed to largeneed to reallocate channel table
 | 
			
		||||
        ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table);
 | 
			
		||||
| 
						 | 
				
			
			@ -1090,7 +1100,7 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co
 | 
			
		|||
        ns_dyn_mem_free(fhss_structure->ws->tr51_output_table);
 | 
			
		||||
        fhss_structure->ws->tr51_output_table = NULL;
 | 
			
		||||
 | 
			
		||||
        if (fhss_ws_manage_channel_table_allocation(fhss_structure, channel_count_uc > channel_count ? channel_count_uc : channel_count)) {
 | 
			
		||||
        if (fhss_ws_manage_channel_table_allocation(fhss_structure, channel_count_uc > channel_count_bc ? channel_count_uc : channel_count_bc)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1113,10 +1123,11 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co
 | 
			
		|||
        for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
            fhss_structure->ws->fhss_configuration.unicast_channel_mask[i] = fhss_configuration->channel_mask[i];
 | 
			
		||||
        }
 | 
			
		||||
        channel_count_uc = channel_count;
 | 
			
		||||
        channel_count_uc = channel_count_bc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fhss_structure->number_of_channels = channel_count;
 | 
			
		||||
    fhss_structure->number_of_channels = fhss_configuration->channel_mask_size;
 | 
			
		||||
    fhss_structure->number_of_bc_channels = channel_count_bc;
 | 
			
		||||
    fhss_structure->number_of_uc_channels = channel_count_uc;
 | 
			
		||||
    if (fhss_configuration->ws_uc_channel_function == WS_FIXED_CHANNEL) {
 | 
			
		||||
        fhss_structure->rx_channel = fhss_configuration->unicast_fixed_channel;
 | 
			
		||||
| 
						 | 
				
			
			@ -1127,7 +1138,7 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co
 | 
			
		|||
            fhss_structure->ws->fhss_configuration.broadcast_fixed_channel,
 | 
			
		||||
            fhss_structure->ws->fhss_configuration.ws_uc_channel_function,
 | 
			
		||||
            fhss_structure->ws->fhss_configuration.ws_bc_channel_function,
 | 
			
		||||
            fhss_structure->number_of_channels,
 | 
			
		||||
            fhss_structure->number_of_bc_channels,
 | 
			
		||||
            fhss_structure->number_of_uc_channels,
 | 
			
		||||
            fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval,
 | 
			
		||||
            fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,8 +19,10 @@
 | 
			
		|||
 | 
			
		||||
// TX slot length is optimised to this packet length
 | 
			
		||||
#define OPTIMAL_PACKET_LENGTH   500
 | 
			
		||||
// Default TX/RX slot length in milliseconds. Is used when datarate is not given by PHY.
 | 
			
		||||
#define WS_TXRX_SLOT_LEN_MS             100
 | 
			
		||||
// Max TX/RX slot length in milliseconds. Is used when datarate is not given by PHY or calculated slot length exceeds maximum allowed.
 | 
			
		||||
#define WS_TXRX_SLOT_LEN_MS_MAX         100
 | 
			
		||||
// Min TX/RX slot length in milliseconds. Is used when calculated slot length is under minimum allowed.
 | 
			
		||||
#define WS_TXRX_SLOT_LEN_MS_MIN         10
 | 
			
		||||
// Default minimum broadcast synchronization interval in seconds
 | 
			
		||||
#define DEFAULT_MIN_SYNCH_INTERVAL      60
 | 
			
		||||
// Drift compensation allowed if at least SYNCH_COMPENSATION_MIN_INTERVAL (seconds) since last synchronization
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,157 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020, Arm Limited and affiliates.
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "nsconfig.h"
 | 
			
		||||
#include "ns_types.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
#include "ns_trace.h"
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
#include "randLIB.h"
 | 
			
		||||
#include "Service_Libs/random_early_detection/random_early_detection.h"
 | 
			
		||||
#include "Service_Libs/random_early_detection/random_early_detection_api.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
red_info_t *random_early_detection_create(uint16_t threshold_min, uint16_t threshold_max, uint8_t drop_max_p, uint16_t weight)
 | 
			
		||||
{
 | 
			
		||||
    //Weight must be between 1-256
 | 
			
		||||
    if (weight == 0 || weight > 256) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Probability  must be between 1-100
 | 
			
		||||
    if (drop_max_p == 0 || drop_max_p > 100) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Max Threshold can't smaller or similar than min
 | 
			
		||||
    if (threshold_max <= threshold_min) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    red_info_t *red_info = ns_dyn_mem_alloc(sizeof(red_info_t));
 | 
			
		||||
    if (red_info) {
 | 
			
		||||
        red_info->count = 0;
 | 
			
		||||
        red_info->averageQ = 0;
 | 
			
		||||
        red_info->parameters.drop_maX_P = drop_max_p;
 | 
			
		||||
        red_info->parameters.threshold_max = threshold_max;
 | 
			
		||||
        red_info->parameters.threshold_min = threshold_min;
 | 
			
		||||
        red_info->parameters.weight = weight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return red_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void random_early_detection_free(struct red_info_s *red_info)
 | 
			
		||||
{
 | 
			
		||||
    ns_dyn_mem_free(red_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//calculate average and return averaged value back
 | 
			
		||||
uint16_t random_early_detetction_aq_calc(red_info_t *red_info, uint16_t sampleLen)
 | 
			
		||||
{
 | 
			
		||||
    if (!red_info) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (red_info->parameters.weight == RED_AVERAGE_WEIGHT_DISABLED || red_info->averageQ == 0) {
 | 
			
		||||
        red_info->averageQ = sampleLen * 256;
 | 
			
		||||
        return sampleLen;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AQ = (1-weight) * average_queue + weight*sampleLen
 | 
			
		||||
    // Now Sample is scaled by 256 which is not loosing so much tail at average
 | 
			
		||||
 | 
			
		||||
    //Weight Last Average part (1-weight) * average_queue with scaled 256
 | 
			
		||||
    uint32_t averageSum = ((256 - red_info->parameters.weight) * red_info->averageQ) / 256;
 | 
			
		||||
    //Add new weighted sample lenght (weight*sampleLen)
 | 
			
		||||
    averageSum += (red_info->parameters.weight * sampleLen);
 | 
			
		||||
 | 
			
		||||
    if (averageSum & 1) {
 | 
			
		||||
        //If sum is ODD add 1 this will help to not stuck like 1,99 average to -> 2
 | 
			
		||||
        averageSum++;
 | 
			
		||||
    }
 | 
			
		||||
    //Store new average
 | 
			
		||||
    red_info->averageQ = averageSum;
 | 
			
		||||
    //Return always same format scaled than inn
 | 
			
		||||
    return red_info->averageQ / 256;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t random_early_detetction_aq_read(red_info_t *red_info)
 | 
			
		||||
{
 | 
			
		||||
    if (!red_info) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return red_info->averageQ / 256;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool random_early_detection_congestion_check(red_info_t *red_info)
 | 
			
		||||
{
 | 
			
		||||
    if (!red_info) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Calulate Average queue size
 | 
			
		||||
    uint16_t sampleLen = red_info->averageQ / 256;;
 | 
			
		||||
 | 
			
		||||
    if (sampleLen <= red_info->parameters.threshold_min) {
 | 
			
		||||
        //Can be added to queue without any RED operation
 | 
			
		||||
        red_info->count = 0;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sampleLen > red_info->parameters.threshold_max) {
 | 
			
		||||
        //Always drop over threshold_max
 | 
			
		||||
        red_info->count = 0;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Calculate probability for packet drop
 | 
			
		||||
    // tempP = drop_maX_P *(AQ - threshold_min) / (threshold_max - threshold_min);
 | 
			
		||||
    uint32_t tempP = (uint32_t) red_info->parameters.drop_maX_P * PROB_SCALE
 | 
			
		||||
                     * (sampleLen  - red_info->parameters.threshold_min)
 | 
			
		||||
                     / (red_info->parameters.threshold_max - red_info->parameters.threshold_min);
 | 
			
		||||
 | 
			
		||||
    // Next Prob = tempP / (1 - count*tempP)
 | 
			
		||||
    // This will increase probability and
 | 
			
		||||
 | 
			
		||||
    //Calculate first divider part
 | 
			
		||||
    uint32_t Prob = red_info->count * tempP;
 | 
			
		||||
 | 
			
		||||
    //Check that divider it is not  >= 0
 | 
			
		||||
    if (Prob >=  PROB_SCALE_MAX) {
 | 
			
		||||
 | 
			
		||||
        red_info->count = 0;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Calculate only when count * tempP is smaller than scaler
 | 
			
		||||
    Prob = (tempP * PROB_SCALE_MAX) / (PROB_SCALE_MAX - Prob);
 | 
			
		||||
    if (Prob > randLIB_get_random_in_range(0, PROX_MAX_RANDOM)) {
 | 
			
		||||
        //Drop packet
 | 
			
		||||
        red_info->count = 0;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Increment count next round check
 | 
			
		||||
    red_info->count++;
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020, Arm Limited and affiliates.
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SERVICE_LIBS_RANDOM_EARLY_DETECTION_RANDOM_EARLY_DETECTION_H_
 | 
			
		||||
#define SERVICE_LIBS_RANDOM_EARLY_DETECTION_RANDOM_EARLY_DETECTION_H_
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//This value cant be bigger than 655
 | 
			
		||||
#define PROB_SCALE 512
 | 
			
		||||
#define PROB_SCALE_MAX PROB_SCALE * 100
 | 
			
		||||
#define PROX_MAX_RANDOM PROB_SCALE_MAX-1
 | 
			
		||||
 | 
			
		||||
typedef struct red_config_s {
 | 
			
		||||
    uint16_t weight;            /*< Weight for new sample len, 256 disabled average */
 | 
			
		||||
    uint16_t threshold_min;     /*< Threshold Min value which start possibility start drop a packet */
 | 
			
		||||
    uint16_t threshold_max;     /*< Threshold Max this value give max Probability for configured value over that every new packet will be dropped*/
 | 
			
		||||
    uint8_t drop_maX_P;         /*< Max probability for drop packet between threshold_min and threshold_max threshold */
 | 
			
		||||
} red_config_t;
 | 
			
		||||
 | 
			
		||||
typedef struct red_info_s {
 | 
			
		||||
    red_config_t parameters;    /*< Random Early detetction parameters for queue avarge and packet drop */
 | 
			
		||||
    uint32_t averageQ;          /*< Average queue size Scaled by 256 1.0 is 256 */
 | 
			
		||||
    uint16_t count;             /*< Missed Packet drop's. This value is incremented when average queue is over min threshoild and packet is noot dropped */
 | 
			
		||||
} red_info_t;
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* SERVICE_LIBS_RANDOM_EARLY_DETECTION_RANDOM_EARLY_DETECTION_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,128 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020, Arm Limited and affiliates.
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SERVICE_LIBS_RANDOM_EARLY_DETECTION_RANDOM_EARLY_DETECTION_API_H_
 | 
			
		||||
#define SERVICE_LIBS_RANDOM_EARLY_DETECTION_RANDOM_EARLY_DETECTION_API_H_
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct red_info_s;
 | 
			
		||||
 | 
			
		||||
#define RED_AVERAGE_WEIGHT_DISABLED 256     /*< Average is disabled */
 | 
			
		||||
#define RED_AVERAGE_WEIGHT_HALF     128     /*< Average weight for new sample is 0.5*new + 0.5 to last one */
 | 
			
		||||
#define RED_AVERAGE_WEIGHT_QUARTER  64      /*< Average weight for new sample is 1/4 + 3/4 to last one */
 | 
			
		||||
#define RED_AVERAGE_WEIGHT_EIGHTH   32      /*< Average weight for new sample is 1/8 + 7/8 to last one */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Create Random early detection data
 | 
			
		||||
 *
 | 
			
		||||
 * Function will config parameters how wide are Random Early detection drop will work.
 | 
			
		||||
 *
 | 
			
		||||
 * How to use parameters:
 | 
			
		||||
 *
 | 
			
		||||
 * Weight is definition how message queue Average (AQ) is calculated. Smaller weight will give smoother AQ update.
 | 
			
		||||
 *
 | 
			
		||||
 *  AQ = (1-weight) * average_queue + weight*sampleLen;
 | 
			
		||||
 *
 | 
			
		||||
 *  * RED_AVERAGE_WEIGHT_DISABLED disable Average by max weight to new sample length
 | 
			
		||||
 *  * RED_AVERAGE_WEIGHT_HALF last average*0.5 + 0.5*new sample: Smooth Average light packet filter
 | 
			
		||||
 *  * RED_AVERAGE_WEIGHT_QUARTER last average*0.75 + 0.25*new sample: Medium packet burst filtering
 | 
			
		||||
 *  * RED_AVERAGE_WEIGHT_EIGHTH last average*7/8 + 1/8*new sample: Good for filtering packet burst and big networks
 | 
			
		||||
 *
 | 
			
		||||
 * How to configure packet drop possibility:
 | 
			
		||||
 *
 | 
			
		||||
 * Define base Probability based current AQ, average length
 | 
			
		||||
 *
 | 
			
		||||
 * tempP = drop_maX_P *(AQ - threshold_min) / (threshold_max - threshold_min);
 | 
			
		||||
 *
 | 
			
		||||
 * Prob = tempP / (1 - count*tempP)
 | 
			
		||||
 *
 | 
			
		||||
 * threshold_min and threshold_max threshold define area for random early detection drop. When Average queue size go over Min threshold packet may drop by given maxProbability.
 | 
			
		||||
 * System will work smoother if min -max threshold range is wide. Then random drop is may cover small data burst until Max threshold Avarage is reached.
 | 
			
		||||
 * After Max every new packet will be dropped.
 | 
			
		||||
 *
 | 
			
		||||
 * Config Examples.
 | 
			
		||||
 *
 | 
			
		||||
 * Threshold values must be set how much device can buffer data.
 | 
			
		||||
 *
 | 
			
		||||
 * Small size data buffering:
 | 
			
		||||
 * random_early_detection_create(32, 96, 10, RED_AVERAGE_WEIGHT_QUARTER)
 | 
			
		||||
 *
 | 
			
		||||
 * Medium size data buffering:
 | 
			
		||||
 * random_early_detection_create(96, 256, 10, RED_AVERAGE_WEIGHT_EIGHTH)
 | 
			
		||||
 *
 | 
			
		||||
 * High size buffering:
 | 
			
		||||
 * random_early_detection_create(256, 600, 10, RED_AVERAGE_WEIGHT_EIGHTH)
 | 
			
		||||
 *
 | 
			
		||||
 * \param threshold_min min average queue size which enable packet drop
 | 
			
		||||
 * \param threshold_max average queue size when all new packets start drop
 | 
			
		||||
 * \param drop_maX_P is percent probability to drop packet 100-1 are possible values
 | 
			
		||||
 * \param weight accepted values 256-1, 256 is 1.0 weight which mean that new queue size overwrite old. 128 is 0.5 which gives 0.5 from old + 0.5 from new.
 | 
			
		||||
 * \return Pointer for allocated structure, NULL if memory allocation fail
 | 
			
		||||
 */
 | 
			
		||||
struct red_info_s *random_early_detection_create(uint16_t threshold_min, uint16_t threshold_max, uint8_t drop_maX_P, uint16_t weight);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Free Random early detection data
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * \param red_info pointer to data
 | 
			
		||||
 */
 | 
			
		||||
void random_early_detection_free(struct red_info_s *red_info);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Random early detection drop function
 | 
			
		||||
 *
 | 
			
		||||
 * \param red_info pointer, which is created user include all configurations
 | 
			
		||||
 * \param sampleLen Current queue length
 | 
			
		||||
 * \return true Drop packet
 | 
			
		||||
 * \return false Packet can be added to queue
 | 
			
		||||
 */
 | 
			
		||||
bool random_early_detection_congestion_check(struct red_info_s *red_info);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Random early detection Average queue calculate
 | 
			
		||||
 *
 | 
			
		||||
 *  Call this when add or remove from queue
 | 
			
		||||
 *
 | 
			
		||||
 * \param red_info pointer, which is created user include all configurations
 | 
			
		||||
 * \param sampleLen Current queue length
 | 
			
		||||
 *
 | 
			
		||||
 * \return New average
 | 
			
		||||
 */
 | 
			
		||||
uint16_t random_early_detetction_aq_calc(struct red_info_s *red_info, uint16_t sampleLen);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Read Random early detection Average queue size
 | 
			
		||||
 *
 | 
			
		||||
 *  Call this when add or remove from queue
 | 
			
		||||
 *
 | 
			
		||||
 * \param red_info pointer, which is created user include all configurations
 | 
			
		||||
 *
 | 
			
		||||
 * \return Current average
 | 
			
		||||
 */
 | 
			
		||||
uint16_t random_early_detetction_aq_read(struct red_info_s *red_info);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* SERVICE_LIBS_RANDOM_EARLY_DETECTION_RANDOM_EARLY_DETECTION_API_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
 | 
			
		||||
#include "nsconfig.h"
 | 
			
		||||
#include "ns_types.h"
 | 
			
		||||
 | 
			
		||||
#include "eventOS_event.h"
 | 
			
		||||
#include "Core/include/ns_monitor.h"
 | 
			
		||||
#include "mac_api.h"    // for mcps_packet_ingress_rate_limit_by_memory
 | 
			
		||||
#include "MAC/IEEE802_15_4/mac_mcps_sap.h" // for mcps_packet_ingress_rate_limit_by_memory
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,9 +29,10 @@
 | 
			
		|||
#include "socket_api.h"
 | 
			
		||||
#include "net_interface.h"
 | 
			
		||||
#include "common_functions.h"
 | 
			
		||||
 | 
			
		||||
#include "libDHCPv6/libDHCPv6.h"
 | 
			
		||||
#include "NWK_INTERFACE/Include/protocol.h" // just for protocol_core_monotonic_time
 | 
			
		||||
 | 
			
		||||
#include "Common_Protocols/ip.h"
 | 
			
		||||
#include "dhcp_service_api.h"
 | 
			
		||||
#ifdef HAVE_DHCPV6
 | 
			
		||||
#define TRACE_GROUP    "dhcp"
 | 
			
		||||
| 
						 | 
				
			
			@ -437,7 +438,7 @@ void recv_dhcp_relay_msg(void *cb_res)
 | 
			
		|||
    uint8_t *ptr = msg_iov[1].iov_base;
 | 
			
		||||
    uint8_t msg_type = *ptr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    int16_t tc = 0;
 | 
			
		||||
    if (msg_type == DHCPV6_RELAY_FORWARD) {
 | 
			
		||||
        tr_error("Drop not supported DHCPv6 forward at Agent");
 | 
			
		||||
        goto cleanup;
 | 
			
		||||
| 
						 | 
				
			
			@ -497,7 +498,10 @@ void recv_dhcp_relay_msg(void *cb_res)
 | 
			
		|||
        msg_iov[0].iov_len = 38;
 | 
			
		||||
        msg_iov[1].iov_len = msg_len;
 | 
			
		||||
        tr_debug("Forward Client msg to server");
 | 
			
		||||
        tc = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    socket_setsockopt(sckt_data->socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc));
 | 
			
		||||
    socket_sendmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0);
 | 
			
		||||
cleanup:
 | 
			
		||||
    ns_dyn_mem_free(msg_iov[1].iov_base);
 | 
			
		||||
| 
						 | 
				
			
			@ -845,6 +849,8 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr)
 | 
			
		|||
 | 
			
		||||
    if (msg_tr_ptr->relay_start) {
 | 
			
		||||
        //Build Relay Reply only server do this
 | 
			
		||||
        int16_t tc = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT;
 | 
			
		||||
        socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc));
 | 
			
		||||
        ns_iovec_t data_vector[2];
 | 
			
		||||
        ns_msghdr_t msghdr;
 | 
			
		||||
        memcpy(msg_tr_ptr->addr.address, msg_tr_ptr->relay_start + 2, 16);
 | 
			
		||||
| 
						 | 
				
			
			@ -872,6 +878,8 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr)
 | 
			
		|||
        retval = socket_sendmsg(msg_tr_ptr->socket, &msghdr, NS_MSG_LEGACY0);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        int16_t tc = 0;
 | 
			
		||||
        socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc));
 | 
			
		||||
        retval = socket_sendto(msg_tr_ptr->socket, &msg_tr_ptr->addr, msg_tr_ptr->msg_ptr, msg_tr_ptr->msg_len);
 | 
			
		||||
    }
 | 
			
		||||
    if (retval != 0) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -165,6 +165,7 @@ SRCS += \
 | 
			
		|||
	source/Service_Libs/Trickle/trickle.c \
 | 
			
		||||
	source/Service_Libs/whiteboard/whiteboard.c \
 | 
			
		||||
	source/Service_Libs/pan_blacklist/pan_blacklist.c \
 | 
			
		||||
	source/Service_Libs/random_early_detection/random_early_detection.c \
 | 
			
		||||
	source/6LoWPAN/Thread/thread_management_if.c \
 | 
			
		||||
	source/6LoWPAN/Thread/thread_management_api.c \
 | 
			
		||||
	source/6LoWPAN/Thread/thread_commissioning_api.c \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue