mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Merge pull request #12481 from artokin/nanostack_release_for_mbed_os_6
Nanostack release for Mbed OS 6pull/12510/head
						commit
						18ad99a883
					
				| 
						 | 
				
			
			@ -209,8 +209,8 @@ static rf_mode_e rf_mode = RF_MODE_NORMAL;
 | 
			
		|||
static bool rf_update_config = false;
 | 
			
		||||
static uint16_t cur_packet_len = 0xffff;
 | 
			
		||||
static uint32_t receiver_ready_timestamp;
 | 
			
		||||
 | 
			
		||||
static int16_t rssi_threshold = RSSI_THRESHOLD;
 | 
			
		||||
static uint32_t tx_start_time = 0;
 | 
			
		||||
 | 
			
		||||
/* Channel configurations for sub-GHz */
 | 
			
		||||
static phy_rf_channel_configuration_s phy_subghz = {
 | 
			
		||||
| 
						 | 
				
			
			@ -276,6 +276,20 @@ static uint32_t rf_get_timestamp(void)
 | 
			
		|||
    return (uint32_t)rf->tx_timer.read_us();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rf_update_tx_active_time(void)
 | 
			
		||||
{
 | 
			
		||||
    if (device_driver.phy_rf_statistics) {
 | 
			
		||||
        device_driver.phy_rf_statistics->tx_active_time += rf_get_timestamp() - tx_start_time;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rf_update_rx_active_time(void)
 | 
			
		||||
{
 | 
			
		||||
    if (device_driver.phy_rf_statistics) {
 | 
			
		||||
        device_driver.phy_rf_statistics->rx_active_time += rf_get_timestamp() - rx_time;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rf_lock(void)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
| 
						 | 
				
			
			@ -739,6 +753,7 @@ static void rf_tx_sent_handler(void)
 | 
			
		|||
    rf_disable_interrupt(TX_DATA_SENT);
 | 
			
		||||
    if (rf_state != RF_TX_ACK) {
 | 
			
		||||
        tx_finnish_time = rf_get_timestamp();
 | 
			
		||||
        rf_update_tx_active_time();
 | 
			
		||||
        TEST_TX_DONE
 | 
			
		||||
        rf_state = RF_IDLE;
 | 
			
		||||
        rf_receive(rf_rx_channel);
 | 
			
		||||
| 
						 | 
				
			
			@ -771,6 +786,7 @@ static void rf_start_tx(void)
 | 
			
		|||
    rf_disable_all_interrupts();
 | 
			
		||||
    rf_poll_state_change(S2LP_STATE_READY);
 | 
			
		||||
    rf_state_change(S2LP_STATE_TX, false);
 | 
			
		||||
    tx_start_time = rf_get_timestamp();
 | 
			
		||||
    // More TX data to be written in FIFO when TX threshold interrupt occurs
 | 
			
		||||
    if (tx_data_ptr) {
 | 
			
		||||
        rf_enable_interrupt(TX_FIFO_ALMOST_EMPTY);
 | 
			
		||||
| 
						 | 
				
			
			@ -805,6 +821,7 @@ static void rf_cca_timer_interrupt(void)
 | 
			
		|||
        }
 | 
			
		||||
        rf_flush_tx_fifo();
 | 
			
		||||
        tx_finnish_time = rf_get_timestamp();
 | 
			
		||||
        rf_update_tx_active_time();
 | 
			
		||||
        if (device_driver.phy_tx_done_cb) {
 | 
			
		||||
            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -825,6 +842,9 @@ static void rf_cca_timer_interrupt(void)
 | 
			
		|||
            rf_start_tx();
 | 
			
		||||
            rf_state = RF_TX_STARTED;
 | 
			
		||||
            TEST_TX_STARTED
 | 
			
		||||
            if (device_driver.phy_rf_statistics) {
 | 
			
		||||
                device_driver.phy_rf_statistics->tx_bytes += tx_data_length;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -843,10 +863,12 @@ static void rf_backup_timer_interrupt(void)
 | 
			
		|||
{
 | 
			
		||||
    tx_finnish_time = rf_get_timestamp();
 | 
			
		||||
    if (rf_state == RF_RX_STARTED) {
 | 
			
		||||
        rf_update_rx_active_time();
 | 
			
		||||
        if (device_driver.phy_rf_statistics) {
 | 
			
		||||
            device_driver.phy_rf_statistics->rx_timeouts++;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        rf_update_tx_active_time();
 | 
			
		||||
        if (device_driver.phy_rf_statistics) {
 | 
			
		||||
            device_driver.phy_rf_statistics->tx_timeouts++;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -921,6 +943,9 @@ static void rf_send_ack(uint8_t seq)
 | 
			
		|||
    rf_start_tx();
 | 
			
		||||
    TEST_ACK_TX_STARTED
 | 
			
		||||
    rf_backup_timer_start(ACK_SENDING_TIME);
 | 
			
		||||
    if (device_driver.phy_rf_statistics) {
 | 
			
		||||
        device_driver.phy_rf_statistics->tx_bytes += sizeof(ack_frame);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rf_handle_ack(uint8_t seq_number, uint8_t pending)
 | 
			
		||||
| 
						 | 
				
			
			@ -928,6 +953,7 @@ static void rf_handle_ack(uint8_t seq_number, uint8_t pending)
 | 
			
		|||
    phy_link_tx_status_e phy_status;
 | 
			
		||||
    if (tx_sequence == (uint16_t)seq_number) {
 | 
			
		||||
        tx_finnish_time = rf_get_timestamp();
 | 
			
		||||
        rf_update_tx_active_time();
 | 
			
		||||
        if (pending) {
 | 
			
		||||
            phy_status = PHY_LINK_TX_DONE_PENDING;
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -966,6 +992,9 @@ static void rf_rx_ready_handler(void)
 | 
			
		|||
                rf_send_ack(rx_buffer[2]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (device_driver.phy_rf_statistics) {
 | 
			
		||||
            device_driver.phy_rf_statistics->rx_bytes += rx_data_length;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        rf_state = RF_IDLE;
 | 
			
		||||
        int8_t rssi = (rf_read_register(RSSI_LEVEL) - RSSI_OFFSET);
 | 
			
		||||
| 
						 | 
				
			
			@ -1072,6 +1101,7 @@ static void rf_irq_task_process_irq(void)
 | 
			
		|||
    if ((irq_status & (1 << TX_FIFO_UNF_OVF)) && (enabled_interrupts & (1 << TX_FIFO_UNF_OVF))) {
 | 
			
		||||
        rf_backup_timer_stop();
 | 
			
		||||
        tx_finnish_time = rf_get_timestamp();
 | 
			
		||||
        rf_update_tx_active_time();
 | 
			
		||||
        TEST_TX_DONE
 | 
			
		||||
        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 0);
 | 
			
		||||
        rf_send_command(S2LP_CMD_SABORT);
 | 
			
		||||
| 
						 | 
				
			
			@ -1087,6 +1117,7 @@ static void rf_irq_task_process_irq(void)
 | 
			
		|||
        }
 | 
			
		||||
    } else if (rf_state == RF_RX_STARTED) {
 | 
			
		||||
        if ((irq_status & (1 << RX_DATA_READY)) && (enabled_interrupts & (1 << RX_DATA_READY))) {
 | 
			
		||||
            rf_update_rx_active_time();
 | 
			
		||||
            if (!(irq_status & (1 << CRC_ERROR))) {
 | 
			
		||||
                rf_rx_ready_handler();
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,6 +1143,7 @@ static void rf_irq_task_process_irq(void)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if ((irq_status & (1 << RX_FIFO_UNF_OVF)) && (enabled_interrupts & (1 << RX_FIFO_UNF_OVF))) {
 | 
			
		||||
        rf_update_rx_active_time();
 | 
			
		||||
        TEST_RX_DONE
 | 
			
		||||
        rf_backup_timer_stop();
 | 
			
		||||
        rf_send_command(S2LP_CMD_SABORT);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -122,9 +122,10 @@ typedef void fhss_data_tx_done(const fhss_api_t *api, bool waiting_ack, bool tx_
 | 
			
		|||
 * @param api FHSS instance.
 | 
			
		||||
 * @param handle Handle of the data request.
 | 
			
		||||
 * @param frame_type Frame type of packet (Frames types are defined by FHSS api).
 | 
			
		||||
 * @param channel Channel wanted to black list temporarily.
 | 
			
		||||
 * @return true if frame has to be queued for retransmission, false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_type);
 | 
			
		||||
typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Change synchronization state.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file fhss_test_api.h
 | 
			
		||||
 * \brief
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef FHSS_TEST_API_H
 | 
			
		||||
#define FHSS_TEST_API_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Set optimal packet length
 | 
			
		||||
  *
 | 
			
		||||
  * \param fhss_api FHSS instance.
 | 
			
		||||
  * \param packet_length Optimal packet length
 | 
			
		||||
  *
 | 
			
		||||
  * \return  0 Success
 | 
			
		||||
  * \return -1 Failure
 | 
			
		||||
  */
 | 
			
		||||
int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // FHSS_TEST_API_H
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +161,8 @@ typedef enum {
 | 
			
		|||
    CHANNEL_PAGE_5 = 5,     ///< Page 5
 | 
			
		||||
    CHANNEL_PAGE_6 = 6,     ///< Page 6
 | 
			
		||||
    CHANNEL_PAGE_9 = 9,     ///< Page 9
 | 
			
		||||
    CHANNEL_PAGE_10 = 10    ///< Page 10
 | 
			
		||||
    CHANNEL_PAGE_10 = 10,   ///< Page 10
 | 
			
		||||
    CHANNEL_PAGE_UNDEFINED  ///< Undefined
 | 
			
		||||
} channel_page_e;
 | 
			
		||||
 | 
			
		||||
/** Modulation index */
 | 
			
		||||
| 
						 | 
				
			
			@ -192,6 +193,10 @@ typedef struct phy_rf_statistics_s {
 | 
			
		|||
    uint32_t crc_fails;        ///< CRC failures
 | 
			
		||||
    uint32_t tx_timeouts;      ///< transmission timeouts
 | 
			
		||||
    uint32_t rx_timeouts;      ///< reception timeouts
 | 
			
		||||
    uint64_t tx_active_time;   ///< transmission active time
 | 
			
		||||
    uint64_t rx_active_time;   ///< reception active time
 | 
			
		||||
    uint32_t tx_bytes;         ///< transmitted bytes
 | 
			
		||||
    uint32_t rx_bytes;         ///< received bytes
 | 
			
		||||
} phy_rf_statistics_s;
 | 
			
		||||
 | 
			
		||||
/** Virtual data request */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,13 @@ extern int8_t ns_sw_mac_virtual_client_unregister(struct mac_api_s *api);
 | 
			
		|||
 */
 | 
			
		||||
extern int ns_sw_mac_fhss_register(struct mac_api_s *mac_api, struct fhss_api *fhss_api);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Unregister FHSS API instance from given software MAC instance.
 | 
			
		||||
 * @param mac_api MAC instance.
 | 
			
		||||
 * @return 0 on success, -1 on fail.
 | 
			
		||||
 */
 | 
			
		||||
extern int ns_sw_mac_fhss_unregister(struct mac_api_s *mac_api);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Request registered FHSS API instance from software MAC instance.
 | 
			
		||||
 * @param mac_api MAC instance.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,11 +51,7 @@ int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id);
 | 
			
		|||
#define BBR_ULA_C                 0x0001 /**< Static ULA prefix created automatically */
 | 
			
		||||
#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 */
 | 
			
		||||
 | 
			
		||||
/*Deprecated configuration values */
 | 
			
		||||
#define BBR_GUA_C           0x0000 /**< Routable prefix is learned from the backbone */
 | 
			
		||||
#define BBR_GUA_SLAAC       0x0000 /**< Use SLAAC addressing in routable prefix */
 | 
			
		||||
#define BBR_GUA_WAIT        0x0000 /**< Wait backbone availability before startingRPL dodag */
 | 
			
		||||
#define BBR_DEFAULT_ROUTE         0x0008 /**< Add default route parameter to DIO */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configure border router features.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1379,6 +1379,8 @@ static int8_t arm_6lowpan_bootstrap_down(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    }
 | 
			
		||||
    cur->if_lowpan_security_params->mle_security_frame_counter = mle_service_security_get_frame_counter(cur->id);
 | 
			
		||||
    mle_service_interface_receiver_handler_update(cur->id, mle_6lowpan_message_handler);
 | 
			
		||||
    // Reset MAC for safe upper layer memory free
 | 
			
		||||
    protocol_mac_reset(cur);
 | 
			
		||||
    return nwk_6lowpan_down(cur);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAVE_6LOWPAN_ND
 | 
			
		||||
| 
						 | 
				
			
			@ -1593,7 +1595,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr
 | 
			
		|||
{
 | 
			
		||||
 | 
			
		||||
    protocol_interface_info_entry_t *cur_interface = user_data;
 | 
			
		||||
    lowpan_adaptation_remove_free_indirect_table(cur_interface, entry_ptr);
 | 
			
		||||
    lowpan_adaptation_neigh_remove_free_tx_tables(cur_interface, entry_ptr);
 | 
			
		||||
    // Sleepy host
 | 
			
		||||
    if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
 | 
			
		||||
        mac_data_poll_protocol_poll_mode_decrement(cur_interface);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,15 @@
 | 
			
		|||
#include "6LoWPAN/Fragmentation/cipv6_fragmenter.h"
 | 
			
		||||
#include "libNET/src/net_load_balance_internal.h"
 | 
			
		||||
 | 
			
		||||
void protocol_mac_reset(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    if (cur->mac_api) {
 | 
			
		||||
        mlme_reset_t reset;
 | 
			
		||||
        reset.SetDefaultPIB = true;
 | 
			
		||||
        cur->mac_api->mlme_req(cur->mac_api, MLME_RESET, &reset);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur)
 | 
			
		||||
| 
						 | 
				
			
			@ -96,15 +105,11 @@ static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur)
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        if (cur->interface_mode == INTERFACE_UP) {
 | 
			
		||||
            if (cur->mac_api) {
 | 
			
		||||
                mlme_reset_t reset;
 | 
			
		||||
                reset.SetDefaultPIB = true;
 | 
			
		||||
            cur->mac_parameters->pan_id = 0xffff;
 | 
			
		||||
            cur->mac_parameters->SecurityEnabled = false;
 | 
			
		||||
            cur->mac_parameters->security_frame_counter = 0;
 | 
			
		||||
            cur->mac_parameters->mac_security_level = 0;
 | 
			
		||||
                cur->mac_api->mlme_req(cur->mac_api, MLME_RESET, &reset);
 | 
			
		||||
            }
 | 
			
		||||
            protocol_mac_reset(cur);
 | 
			
		||||
            cur->interface_mode = INTERFACE_IDLE;
 | 
			
		||||
            net_load_balance_internal_state_activate(cur, false);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,5 +31,7 @@ extern int8_t nwk_6lowpan_up(struct protocol_interface_info_entry *cur);
 | 
			
		|||
 */
 | 
			
		||||
extern int8_t nwk_6lowpan_down(struct protocol_interface_info_entry *cur);
 | 
			
		||||
 | 
			
		||||
extern void protocol_mac_reset(struct protocol_interface_info_entry *cur);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* PROTOCOL_6LOWPAN_INTERFACE_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -887,6 +887,7 @@ int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_p
 | 
			
		|||
 | 
			
		||||
void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, uint8_t *mac64)
 | 
			
		||||
{
 | 
			
		||||
    (void) mac64;
 | 
			
		||||
    if (!mac_api) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,6 +120,7 @@ void mcps_data_indication_handler(const mac_api_t *api, const mcps_data_ind_t *d
 | 
			
		|||
void mcps_purge_confirm_handler(const mac_api_t *api, mcps_purge_conf_t *data)
 | 
			
		||||
{
 | 
			
		||||
    (void)api;
 | 
			
		||||
    (void)data;
 | 
			
		||||
    tr_info("MCPS Data Purge confirm status %u, for handle %u", data->status, data->msduHandle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -856,9 +856,6 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac
 | 
			
		|||
        mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur_interface), ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh), ADDR_802_15_4_LONG);
 | 
			
		||||
 | 
			
		||||
        if (entry) {
 | 
			
		||||
            if (ws_info(cur_interface)) {
 | 
			
		||||
                ws_common_etx_validate(cur_interface, entry);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!entry->ffd_device) {
 | 
			
		||||
                rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime);
 | 
			
		||||
| 
						 | 
				
			
			@ -931,12 +928,14 @@ 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) &&
 | 
			
		||||
            !ws_common_allow_child_registration(cur_interface, aro_out->eui64)) {
 | 
			
		||||
    if (ws_info(cur_interface)) {
 | 
			
		||||
 | 
			
		||||
        aro_out->status = ws_common_allow_child_registration(cur_interface, aro_out->eui64);
 | 
			
		||||
        if (aro_out->status != ARO_SUCCESS) {
 | 
			
		||||
            aro_out->present = true;
 | 
			
		||||
        aro_out->status = ARO_FULL;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* We need to have entry in the Neighbour Cache */
 | 
			
		||||
    ipv6_neighbour_t *neigh = ipv6_neighbour_lookup_or_create(&cur_interface->ipv6_neighbour_cache, src_addr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1757,6 +1756,8 @@ void nd_6lowpan_set_radv_params(protocol_interface_info_entry_t *cur_interface)
 | 
			
		|||
    cur_interface->adv_retrans_timer = nd_params.ra_retrans_timer;
 | 
			
		||||
    cur_interface->max_initial_rtr_adv_interval = nd_params.ra_interval_min;
 | 
			
		||||
    cur_interface->max_initial_rtr_advertisements = nd_params.ra_transmits;
 | 
			
		||||
#else
 | 
			
		||||
    (void) cur_interface;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#endif // HAVE_6LOWPAN_ND
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,7 +137,7 @@ static void thread_bootstrap_pbbr_update_done(struct protocol_interface_info_ent
 | 
			
		|||
static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
    protocol_interface_info_entry_t *cur = user_data;
 | 
			
		||||
    lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr);
 | 
			
		||||
    lowpan_adaptation_neigh_remove_free_tx_tables(cur, entry_ptr);
 | 
			
		||||
 | 
			
		||||
    thread_reset_neighbour_info(cur, entry_ptr);
 | 
			
		||||
    //Removes ETX neighbor
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -240,6 +240,8 @@ int8_t thread_bootstrap_down(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    tr_debug("SET thread Idle");
 | 
			
		||||
    //stop polling
 | 
			
		||||
    mac_data_poll_disable(cur);
 | 
			
		||||
    // Reset MAC for safe upper layer memory free
 | 
			
		||||
    protocol_mac_reset(cur);
 | 
			
		||||
    //Clean mle table
 | 
			
		||||
    thread_neighbor_list_clean(cur);
 | 
			
		||||
    // store frame counters
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -699,7 +699,7 @@ int thread_dhcpv6_server_set_anonymous_addressing(int8_t interface_id, uint8_t *
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous);
 | 
			
		||||
    return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous, false);
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    (void) prefix_ptr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -285,7 +285,7 @@ static void thread_update_mle_entry(protocol_interface_info_entry_t *cur, mle_me
 | 
			
		|||
    if (short_address != entry_temp->mac16) {
 | 
			
		||||
        if (thread_router_addr_from_addr(entry_temp->mac16) == cur->thread_info->routerShortAddress) {
 | 
			
		||||
            thread_dynamic_storage_child_info_clear(cur->id, entry_temp);
 | 
			
		||||
            protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_temp->mac16);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        entry_temp->mac16 = short_address;
 | 
			
		||||
        /* throw MLME_GET request, short address is changed automatically in get request callback */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,6 +64,7 @@
 | 
			
		|||
#include "Common_Protocols/icmpv6_radv.h"
 | 
			
		||||
#include "MLE/mle.h"
 | 
			
		||||
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
 | 
			
		||||
#include "6LoWPAN/lowpan_adaptation_interface.h"
 | 
			
		||||
#include "6LoWPAN/MAC/mac_helper.h"
 | 
			
		||||
 | 
			
		||||
#define TRACE_GROUP "tsyn"
 | 
			
		||||
| 
						 | 
				
			
			@ -192,15 +193,29 @@ void thread_dynamic_storage_child_info_store(protocol_interface_info_entry_t *cu
 | 
			
		|||
 | 
			
		||||
void thread_dynamic_storage_child_info_clear(int8_t interface_id, struct mac_neighbor_table_entry *child)
 | 
			
		||||
{
 | 
			
		||||
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
 | 
			
		||||
    if (!cur) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    thread_sync_child_info_t *child_info = thread_dynamic_storage_child_info_find(interface_id, child);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (child_info) {
 | 
			
		||||
        // Clear child information
 | 
			
		||||
        memset(child_info, 0, sizeof(thread_sync_child_info_t));
 | 
			
		||||
        tr_debug("Dynamic storage: cleared child; mac16=%04x", child->mac16);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
    uint8_t temp_address[2];
 | 
			
		||||
    common_write_16_bit(child->mac16, temp_address);
 | 
			
		||||
    //Release Old short address entries
 | 
			
		||||
    lowpan_adaptation_free_messages_from_queues_by_address(cur, temp_address, ADDR_802_15_4_SHORT);
 | 
			
		||||
    /* As we are losing a link to a child address, we can assume that if we have an IP neighbour cache
 | 
			
		||||
     * mapping to that address, it is no longer valid. We must have been their parent, and they must be
 | 
			
		||||
     * finding a new parent, and hence a new 16-bit address. (Losing a link to a router address would not
 | 
			
		||||
     * invalidate our IP->16-bit mapping.)
 | 
			
		||||
     */
 | 
			
		||||
    protocol_6lowpan_release_short_link_address_from_neighcache(cur, child->mac16);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static thread_sync_child_info_t *thread_dynamic_storage_child_info_find(int8_t interface_id, mac_neighbor_table_entry_t *child)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -969,13 +969,6 @@ int thread_router_bootstrap_reset_child_info(protocol_interface_info_entry_t *cu
 | 
			
		|||
    tr_debug("Child free %x", child->mac16);
 | 
			
		||||
    thread_dynamic_storage_child_info_clear(cur->id, child);
 | 
			
		||||
 | 
			
		||||
    /* As we are losing a link to a child address, we can assume that if we have an IP neighbour cache
 | 
			
		||||
     * mapping to that address, it is no longer valid. We must have been their parent, and they must be
 | 
			
		||||
     * finding a new parent, and hence a new 16-bit address. (Losing a link to a router address would not
 | 
			
		||||
     * invalidate our IP->16-bit mapping.)
 | 
			
		||||
     */
 | 
			
		||||
    protocol_6lowpan_release_short_link_address_from_neighcache(cur, child->mac16);
 | 
			
		||||
 | 
			
		||||
    // If Child's RLOC16 appears in the Network Data send the RLOC16 to the Leader
 | 
			
		||||
    if (thread_network_data_services_registered(&cur->thread_info->networkDataStorage, child->mac16)) {
 | 
			
		||||
        tr_debug("Remove references to Child's RLOC16 from the Network Data");
 | 
			
		||||
| 
						 | 
				
			
			@ -1824,7 +1817,6 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t *
 | 
			
		|||
                // Was this previously our child? If yes, update.
 | 
			
		||||
                if ((entry_temp->mac16 & THREAD_CHILD_MASK) && thread_router_addr_from_addr(entry_temp->mac16) == cur->thread_info->routerShortAddress) {
 | 
			
		||||
                    thread_dynamic_storage_child_info_clear(cur->id, entry_temp);
 | 
			
		||||
                    protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_temp->mac16);
 | 
			
		||||
                }
 | 
			
		||||
                update_mac_mib = true;
 | 
			
		||||
                entry_temp->mac16 = shortAddress; // short address refreshed
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -643,11 +643,10 @@ int thread_test_version_set(int8_t interface_id, uint8_t version)
 | 
			
		|||
 | 
			
		||||
int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_THREAD
 | 
			
		||||
#if defined(HAVE_THREAD) && defined(HAVE_THREAD_V2) && defined(HAVE_THREAD_BORDER_ROUTER)
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
    thread_bbr_commercial_status_override_set(dua_status, dua_count, ba_failure_count);
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
    (void)dua_status;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,8 +89,8 @@ typedef struct {
 | 
			
		|||
    fragmenter_tx_list_t indirect_tx_queue;
 | 
			
		||||
    uint8_t *fragment_indirect_tx_buffer; //Used for write fragmentation header
 | 
			
		||||
    uint16_t mtu_size;
 | 
			
		||||
    fragmenter_tx_entry_t active_unicast_tx_buf; //Current active direct unicast tx process
 | 
			
		||||
    fragmenter_tx_entry_t active_broadcast_tx_buf; //Current active direct broadcast tx process
 | 
			
		||||
    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 indirect_big_packet_threshold;
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t inter
 | 
			
		|||
 | 
			
		||||
/* Interface direct message pending queue functions */
 | 
			
		||||
static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr, buffer_t *buf);
 | 
			
		||||
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur);
 | 
			
		||||
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr);
 | 
			
		||||
 | 
			
		||||
/* Data direction and message length validation */
 | 
			
		||||
static bool lowpan_adaptation_indirect_data_request(mac_neighbor_table_entry_t *mle_entry);
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +126,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf
 | 
			
		|||
 | 
			
		||||
/* Tx confirmation local functions */
 | 
			
		||||
static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf);
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue);
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_listed_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue);
 | 
			
		||||
static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event);
 | 
			
		||||
static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status);
 | 
			
		||||
static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +138,8 @@ static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interf
 | 
			
		|||
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_adaptation_indirect_mac_data_request_active(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr);
 | 
			
		||||
 | 
			
		||||
static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buffer_t *buf);
 | 
			
		||||
 | 
			
		||||
static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm)
 | 
			
		||||
{
 | 
			
		||||
    switch (confirm->status) {
 | 
			
		||||
| 
						 | 
				
			
			@ -221,18 +223,14 @@ static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_p
 | 
			
		|||
    protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur)
 | 
			
		||||
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr)
 | 
			
		||||
{
 | 
			
		||||
    /* Currently this function is called only when data confirm is received for previously sent packet.
 | 
			
		||||
     * Data confirm has freed the corresponding "active buffer" and this function will look for new buffer to be set as active buffer.
 | 
			
		||||
     */
 | 
			
		||||
    // Currently this function is called only when data confirm is received for previously sent packet.
 | 
			
		||||
    if (!interface_ptr->directTxQueue_size) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    ns_list_foreach_safe(buffer_t, buf, &interface_ptr->directTxQueue) {
 | 
			
		||||
        bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
 | 
			
		||||
        //Check that we not trig second active fragmentation process
 | 
			
		||||
        if (fragmented_needed && interface_ptr->fragmenter_active) {
 | 
			
		||||
            tr_debug("Do not trig Second active fragmentation");
 | 
			
		||||
        } else if ((buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_unicast_tx_buf.buf)
 | 
			
		||||
                   || (!buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_broadcast_tx_buf.buf)) {
 | 
			
		||||
        if (lowpan_buffer_tx_allowed(interface_ptr, buf)) {
 | 
			
		||||
            ns_list_remove(&interface_ptr->directTxQueue, buf);
 | 
			
		||||
            interface_ptr->directTxQueue_size--;
 | 
			
		||||
            protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +290,7 @@ static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue)
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_listed_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach(fragmenter_tx_entry_t, entry, indirect_tx_queue) {
 | 
			
		||||
        if (entry->buf->seq == handle) {
 | 
			
		||||
| 
						 | 
				
			
			@ -310,9 +308,9 @@ static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *int
 | 
			
		|||
    uint8_t handle;
 | 
			
		||||
    while (!valid_info) {
 | 
			
		||||
        handle = interface_ptr->msduHandle++;
 | 
			
		||||
        if (!lowpan_active_tx_handle_verify(handle, interface_ptr->active_unicast_tx_buf.buf)
 | 
			
		||||
        if (!lowpan_listed_tx_handle_verify(handle, &interface_ptr->activeUnicastList)
 | 
			
		||||
                && !lowpan_active_tx_handle_verify(handle, interface_ptr->active_broadcast_tx_buf.buf)
 | 
			
		||||
                && !lowpan_indirect_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) {
 | 
			
		||||
                && !lowpan_listed_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) {
 | 
			
		||||
            valid_info = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +318,7 @@ static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *int
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list, fragmenter_tx_entry_t *entry)
 | 
			
		||||
static void lowpan_list_entry_free(fragmenter_tx_list_t *list, fragmenter_tx_entry_t *entry)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_remove(list, entry);
 | 
			
		||||
    if (entry->buf) {
 | 
			
		||||
| 
						 | 
				
			
			@ -330,11 +328,15 @@ static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list, fragmenter_tx
 | 
			
		|||
    ns_dyn_mem_free(entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lowpan_indirect_queue_free(fragmenter_tx_list_t *list)
 | 
			
		||||
static void lowpan_list_free(fragmenter_tx_list_t *list, bool fragment_buf_free)
 | 
			
		||||
{
 | 
			
		||||
    while (!ns_list_is_empty(list)) {
 | 
			
		||||
        fragmenter_tx_entry_t *entry = ns_list_get_first(list);
 | 
			
		||||
        lowpan_indirect_entry_free(list, entry);
 | 
			
		||||
        if (!fragment_buf_free) {
 | 
			
		||||
            //We can't free this pointer becuase it must be until interface is deleted
 | 
			
		||||
            entry->fragmenter_buf = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        lowpan_list_entry_free(list, entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -365,6 +367,7 @@ 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);
 | 
			
		||||
 | 
			
		||||
    ns_list_add_to_end(&fragmenter_interface_list, interface_ptr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -389,11 +392,11 @@ int8_t lowpan_adaptation_interface_free(int8_t interface_id)
 | 
			
		|||
 | 
			
		||||
    ns_list_remove(&fragmenter_interface_list, interface_ptr);
 | 
			
		||||
    //free active tx process
 | 
			
		||||
    lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
 | 
			
		||||
    lowpan_list_free(&interface_ptr->activeUnicastList, false);
 | 
			
		||||
    lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
 | 
			
		||||
 | 
			
		||||
    //Free Indirect entry
 | 
			
		||||
    lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
 | 
			
		||||
    lowpan_list_free(&interface_ptr->indirect_tx_queue, true);
 | 
			
		||||
 | 
			
		||||
    buffer_free_list(&interface_ptr->directTxQueue);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -414,13 +417,13 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    //free active tx process
 | 
			
		||||
    lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
 | 
			
		||||
    lowpan_list_free(&interface_ptr->activeUnicastList, false);
 | 
			
		||||
    lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
 | 
			
		||||
    //Clean fragmented message flag
 | 
			
		||||
    interface_ptr->fragmenter_active = false;
 | 
			
		||||
 | 
			
		||||
    //Free Indirect entry
 | 
			
		||||
    lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
 | 
			
		||||
    lowpan_list_free(&interface_ptr->indirect_tx_queue, true);
 | 
			
		||||
 | 
			
		||||
    buffer_free_list(&interface_ptr->directTxQueue);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -588,10 +591,15 @@ static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry
 | 
			
		|||
 | 
			
		||||
static fragmenter_tx_entry_t *lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast)
 | 
			
		||||
{
 | 
			
		||||
    // For broadcast, the active TX queue is only 1 entry. For unicast, using a list.
 | 
			
		||||
    fragmenter_tx_entry_t *tx_entry;
 | 
			
		||||
    if (!indirect) {
 | 
			
		||||
        if (is_unicast) {
 | 
			
		||||
            tx_entry = &interface_ptr->active_unicast_tx_buf;
 | 
			
		||||
            tx_entry = lowpan_indirect_entry_allocate(0);
 | 
			
		||||
            if (!tx_entry) {
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
            ns_list_add_to_end(&interface_ptr->activeUnicastList, tx_entry);
 | 
			
		||||
        } else {
 | 
			
		||||
            tx_entry = &interface_ptr->active_broadcast_tx_buf;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -936,6 +944,40 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool lowpan_adaptation_is_destination_tx_active(fragmenter_tx_list_t *list, buffer_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach(fragmenter_tx_entry_t, entry, list) {
 | 
			
		||||
        if (entry->buf) {
 | 
			
		||||
            if (!memcmp(&entry->buf->dst_sa.address[2], &buf->dst_sa.address[2], 8)) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buffer_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
 | 
			
		||||
    // Indirect allowed always
 | 
			
		||||
    if (buf->link_specific.ieee802_15_4.indirectTxProcess) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    // Do not accept any other TX when fragmented TX active. Prevents other frames to be sent in between two fragments.
 | 
			
		||||
    if (interface_ptr->fragmenter_active) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    // Do not accept more than one active broadcast TX
 | 
			
		||||
    if (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf) {
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf)
 | 
			
		||||
{
 | 
			
		||||
    bool is_room_for_new_message;
 | 
			
		||||
| 
						 | 
				
			
			@ -956,11 +998,10 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
 | 
			
		|||
    bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
 | 
			
		||||
    bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
 | 
			
		||||
    bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess;
 | 
			
		||||
    if (!indirect) {
 | 
			
		||||
        if (((is_unicast && interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf)) || (fragmented_needed && interface_ptr->fragmenter_active)) {
 | 
			
		||||
 | 
			
		||||
    if (!lowpan_buffer_tx_allowed(interface_ptr, buf)) {
 | 
			
		||||
        lowpan_adaptation_tx_queue_write(interface_ptr, buf);
 | 
			
		||||
            return 0; //Return here
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Allocate Handle
 | 
			
		||||
| 
						 | 
				
			
			@ -1107,10 +1148,14 @@ static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr)
 | 
			
		|||
static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event)
 | 
			
		||||
{
 | 
			
		||||
    buffer_t *buf = tx_ptr->buf;
 | 
			
		||||
 | 
			
		||||
    tx_ptr->buf = NULL;
 | 
			
		||||
    if (buf->link_specific.ieee802_15_4.indirectTxProcess) {
 | 
			
		||||
        //release from list and free entry
 | 
			
		||||
        lowpan_indirect_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr);
 | 
			
		||||
        lowpan_list_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr);
 | 
			
		||||
    } else if (buf->link_specific.ieee802_15_4.requestAck) {
 | 
			
		||||
        ns_list_remove(&interface_ptr->activeUnicastList, tx_ptr);
 | 
			
		||||
        ns_dyn_mem_free(tx_ptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    socket_tx_buffer_event_and_free(buf, socket_event);
 | 
			
		||||
| 
						 | 
				
			
			@ -1131,18 +1176,19 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
 | 
			
		|||
    //Check first
 | 
			
		||||
    fragmenter_tx_entry_t *tx_ptr;
 | 
			
		||||
    bool active_direct_confirm;
 | 
			
		||||
    bool is_unicast = true;
 | 
			
		||||
 | 
			
		||||
    if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_unicast_tx_buf.buf)) {
 | 
			
		||||
        active_direct_confirm = true;
 | 
			
		||||
        tx_ptr = &interface_ptr->active_unicast_tx_buf;
 | 
			
		||||
    } else if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_broadcast_tx_buf.buf)) {
 | 
			
		||||
    if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_broadcast_tx_buf.buf)) {
 | 
			
		||||
        active_direct_confirm = true;
 | 
			
		||||
        tx_ptr = &interface_ptr->active_broadcast_tx_buf;
 | 
			
		||||
        is_unicast = false;
 | 
			
		||||
    } else {
 | 
			
		||||
        tx_ptr = lowpan_listed_tx_handle_verify(confirm->msduHandle, &interface_ptr->activeUnicastList);
 | 
			
		||||
        if (tx_ptr) {
 | 
			
		||||
            active_direct_confirm = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            tx_ptr = lowpan_listed_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue);
 | 
			
		||||
            if (tx_ptr) {
 | 
			
		||||
                active_direct_confirm = false;
 | 
			
		||||
        tx_ptr = lowpan_indirect_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!tx_ptr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1214,7 +1260,7 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RPL
 | 
			
		||||
            if (confirm->status == MLME_TX_NO_ACK) {
 | 
			
		||||
            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);
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1232,14 +1278,15 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
 | 
			
		|||
            break;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((is_unicast && !interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && !interface_ptr->active_broadcast_tx_buf.buf)) {
 | 
			
		||||
        //Read Buffer and trig next direct request
 | 
			
		||||
        lowpan_adaptation_interface_tx(cur, lowpan_adaptation_tx_queue_read(interface_ptr, cur));
 | 
			
		||||
    // When confirmation is for direct transmission, push all allowed buffers to MAC
 | 
			
		||||
    if (active_direct_confirm == true) {
 | 
			
		||||
        buffer_t *buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr);
 | 
			
		||||
        while (buf_from_queue) {
 | 
			
		||||
            lowpan_adaptation_interface_tx(cur, buf_from_queue);
 | 
			
		||||
            buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool mac_data_is_broadcast_addr(const sockaddr_t *addr)
 | 
			
		||||
| 
						 | 
				
			
			@ -1332,7 +1379,7 @@ bool lowpan_adaptation_tx_active(int8_t interface_id)
 | 
			
		|||
{
 | 
			
		||||
    fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
 | 
			
		||||
 | 
			
		||||
    if (!interface_ptr || (!interface_ptr->active_unicast_tx_buf.buf && !interface_ptr->active_broadcast_tx_buf.buf)) {
 | 
			
		||||
    if (!interface_ptr || (!ns_list_count(&interface_ptr->activeUnicastList) && !interface_ptr->active_broadcast_tx_buf.buf)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -1399,19 +1446,19 @@ static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interf
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lowpan_adaptation_remove_free_indirect_table(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr)
 | 
			
		||||
void lowpan_adaptation_neigh_remove_free_tx_tables(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr)
 | 
			
		||||
{
 | 
			
		||||
    //Free first by defined short address
 | 
			
		||||
    if (entry_ptr->mac16 < 0xfffe) {
 | 
			
		||||
        uint8_t temp_address[2];
 | 
			
		||||
        common_write_16_bit(entry_ptr->mac16, temp_address);
 | 
			
		||||
        lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT);
 | 
			
		||||
        lowpan_adaptation_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT);
 | 
			
		||||
    }
 | 
			
		||||
    lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG);
 | 
			
		||||
    lowpan_adaptation_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type)
 | 
			
		||||
int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type)
 | 
			
		||||
{
 | 
			
		||||
    fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1427,9 +1474,18 @@ int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct pr
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Check next direct queue
 | 
			
		||||
    ns_list_foreach_safe(fragmenter_tx_entry_t, entry, &interface_ptr->activeUnicastList) {
 | 
			
		||||
        if (lowpan_tx_buffer_address_compare(&entry->buf->dst_sa, address_ptr, adr_type)) {
 | 
			
		||||
            //Purge from mac
 | 
			
		||||
            lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, entry);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,9 +51,9 @@ struct buffer *lowpan_adaptation_reassembly(struct protocol_interface_info_entry
 | 
			
		|||
 | 
			
		||||
bool lowpan_adaptation_tx_active(int8_t interface_id);
 | 
			
		||||
 | 
			
		||||
void lowpan_adaptation_remove_free_indirect_table(struct protocol_interface_info_entry *cur_interface, struct mac_neighbor_table_entry *entry_ptr);
 | 
			
		||||
void lowpan_adaptation_neigh_remove_free_tx_tables(struct protocol_interface_info_entry *cur_interface, struct mac_neighbor_table_entry *entry_ptr);
 | 
			
		||||
 | 
			
		||||
int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type);
 | 
			
		||||
int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type);
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,10 +45,10 @@
 | 
			
		|||
 | 
			
		||||
#define RPL_INSTANCE_ID 1
 | 
			
		||||
 | 
			
		||||
static uint8_t current_instance_id = RPL_INSTANCE_ID;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WS_BORDER_ROUTER
 | 
			
		||||
 | 
			
		||||
static uint8_t current_instance_id = RPL_INSTANCE_ID;
 | 
			
		||||
 | 
			
		||||
#define WS_ULA_LIFETIME 24*3600
 | 
			
		||||
#define WS_ROUTE_LIFETIME WS_ULA_LIFETIME
 | 
			
		||||
#define WS_DHCP_ADDRESS_LIFETIME 2*3600
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +85,27 @@ static rpl_dodag_conf_t rpl_conf = {
 | 
			
		|||
    .dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase)
 | 
			
		||||
static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, uint8_t version)
 | 
			
		||||
{
 | 
			
		||||
    // Set the next timeout value for version update
 | 
			
		||||
    if (version < 128) {
 | 
			
		||||
        //stable version for RPL so slow timer update is ok
 | 
			
		||||
        cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME;
 | 
			
		||||
    } else {
 | 
			
		||||
        cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_bbr_rpl_version_increase(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    if (!protocol_6lowpan_rpl_root_dodag) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ws_bbr_rpl_version_timer_start(cur, rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase)
 | 
			
		||||
{
 | 
			
		||||
    if (imin == 0 || doubling == 0) {
 | 
			
		||||
        // use default values
 | 
			
		||||
| 
						 | 
				
			
			@ -111,11 +131,11 @@ void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint1
 | 
			
		|||
 | 
			
		||||
    if (protocol_6lowpan_rpl_root_dodag) {
 | 
			
		||||
        rpl_control_update_dodag_config(protocol_6lowpan_rpl_root_dodag, &rpl_conf);
 | 
			
		||||
        rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
 | 
			
		||||
        ws_bbr_rpl_version_increase(cur);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
 | 
			
		||||
static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id)
 | 
			
		||||
{
 | 
			
		||||
    tr_info("RPL root start");
 | 
			
		||||
    rpl_data_init_root();
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +143,6 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
 | 
			
		|||
    if (protocol_6lowpan_rpl_root_dodag) {
 | 
			
		||||
        rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
 | 
			
		||||
        protocol_6lowpan_rpl_root_dodag = NULL;
 | 
			
		||||
        current_instance_id++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protocol_6lowpan_rpl_root_dodag = rpl_control_create_dodag_root(protocol_6lowpan_rpl_domain, current_instance_id, dodag_id, &rpl_conf, rpl_conf.min_hop_rank_increase, RPL_GROUNDED | RPL_MODE_NON_STORING | RPL_DODAG_PREF(0));
 | 
			
		||||
| 
						 | 
				
			
			@ -133,19 +152,20 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
 | 
			
		|||
    }
 | 
			
		||||
    // RPL memory limits set larger for Border router
 | 
			
		||||
    rpl_control_set_memory_limits(64 * 1024, 0);
 | 
			
		||||
 | 
			
		||||
    // Initial version number for RPL start is 240 from RPL RFC
 | 
			
		||||
    ws_bbr_rpl_version_timer_start(cur, 240);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void ws_bbr_rpl_root_stop(void)
 | 
			
		||||
{
 | 
			
		||||
    tr_info("RPL root stop");
 | 
			
		||||
    if (protocol_6lowpan_rpl_root_dodag) {
 | 
			
		||||
        rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
 | 
			
		||||
        protocol_6lowpan_rpl_root_dodag = NULL;
 | 
			
		||||
        current_instance_id++;
 | 
			
		||||
    }
 | 
			
		||||
    memset(current_local_prefix, 0, 8);
 | 
			
		||||
    memset(current_global_prefix, 0, 8);
 | 
			
		||||
    memset(current_dodag_id, 0, 16);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address)
 | 
			
		||||
| 
						 | 
				
			
			@ -177,11 +197,24 @@ int ws_border_router_proxy_state_update(int8_t caller_interface_id, int8_t handl
 | 
			
		|||
 | 
			
		||||
static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix)
 | 
			
		||||
{
 | 
			
		||||
    if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
 | 
			
		||||
    if_address_entry_t *add_entry = NULL;
 | 
			
		||||
    const uint8_t *address;
 | 
			
		||||
 | 
			
		||||
    address = addr_select_with_prefix(cur, ula_prefix, 64, 0);
 | 
			
		||||
    if (address) {
 | 
			
		||||
        // Address already exists for this prefix find the entry
 | 
			
		||||
        add_entry = addr_get_entry(cur, address);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!add_entry) {
 | 
			
		||||
        add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
 | 
			
		||||
    }
 | 
			
		||||
    if (!add_entry) {
 | 
			
		||||
        tr_err("ula create failed");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    // Set the timeouts for this address and policy
 | 
			
		||||
    icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0xffffffff, 0xffffffff);
 | 
			
		||||
    addr_policy_table_add_entry(ula_prefix, 64, 2, WS_NON_PREFFRED_LABEL);
 | 
			
		||||
    return add_entry;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -307,9 +340,11 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb);
 | 
			
		||||
 | 
			
		||||
    DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true);
 | 
			
		||||
    //Enable SLAAC mode to border router
 | 
			
		||||
    DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false);
 | 
			
		||||
    DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME);
 | 
			
		||||
    //SEt max value for not limiting address allocation
 | 
			
		||||
    DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE);
 | 
			
		||||
 | 
			
		||||
    ws_dhcp_client_address_request(cur, global_id, ll);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -325,6 +360,31 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_bbr_routing_stop(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    tr_info("BBR routing stop");
 | 
			
		||||
    if (memcmp(current_local_prefix, ADDR_UNSPECIFIED, 8) != 0) {
 | 
			
		||||
        ws_bbr_slaac_remove(cur, current_local_prefix);
 | 
			
		||||
        memset(current_local_prefix, 0, 8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) {
 | 
			
		||||
        ws_bbr_dhcp_server_stop(cur, current_global_prefix);
 | 
			
		||||
        if (backbone_interface_id >= 0) {
 | 
			
		||||
            // Delete route to backbone if it exists
 | 
			
		||||
            ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0, 0);
 | 
			
		||||
        }
 | 
			
		||||
        memset(current_global_prefix, 0, 8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 8) != 0) {
 | 
			
		||||
        ws_bbr_slaac_remove(cur, current_dodag_id);
 | 
			
		||||
        memset(current_dodag_id, 0, 16);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_bbr_rpl_root_stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -339,7 +399,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    if (!protocol_6lowpan_rpl_root_dodag) {
 | 
			
		||||
        // Generate DODAGID
 | 
			
		||||
        if (ws_bbr_static_dodagid_create(cur) == 0) {
 | 
			
		||||
            ws_bbr_rpl_root_start(current_dodag_id);
 | 
			
		||||
            ws_bbr_rpl_root_start(cur, current_dodag_id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,9 +414,8 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
     */
 | 
			
		||||
    if (protocol_interface_address_compare(current_dodag_id) != 0) {
 | 
			
		||||
        //DODAGID is lost need to restart
 | 
			
		||||
        tr_warn("DODAGID lost restart RPL");
 | 
			
		||||
        memset(current_dodag_id, 0, 16);
 | 
			
		||||
        ws_bbr_rpl_root_stop();
 | 
			
		||||
        tr_warn("DODAGID lost restart BBR");
 | 
			
		||||
        ws_bbr_routing_stop(cur);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -366,7 +425,9 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    /*
 | 
			
		||||
     * Add default route to RPL
 | 
			
		||||
     */
 | 
			
		||||
    if (configuration & BBR_DEFAULT_ROUTE) {
 | 
			
		||||
        rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Create static ULA configuration or modify if needed
 | 
			
		||||
| 
						 | 
				
			
			@ -384,6 +445,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
 | 
			
		||||
        if (memcmp(local_prefix, ADDR_UNSPECIFIED, 8) != 0) {
 | 
			
		||||
            if (!ws_bbr_slaac_generate(cur, local_prefix)) {
 | 
			
		||||
                // Address creation failed
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -425,8 +487,9 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
            if (configuration & BBR_GUA_ROUTE) {
 | 
			
		||||
                rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, 0, true);
 | 
			
		||||
            }
 | 
			
		||||
            if (backbone_interface_id >= 0) {
 | 
			
		||||
                ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            ws_bbr_dhcp_server_stop(cur, current_global_prefix);
 | 
			
		||||
        }
 | 
			
		||||
        // TODO add global prefix
 | 
			
		||||
| 
						 | 
				
			
			@ -435,10 +498,12 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
            tr_info("RPL global prefix activate %s", trace_ipv6_prefix(global_prefix, 64));
 | 
			
		||||
            // Add default route to RPL
 | 
			
		||||
            // Enable default routing to backbone
 | 
			
		||||
            if (backbone_interface_id >= 0) {
 | 
			
		||||
                if (ipv6_route_add_with_info(global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0) == NULL) {
 | 
			
		||||
                    tr_err("global route add failed");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            ws_bbr_dhcp_server_start(cur, global_prefix);
 | 
			
		||||
            rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false);
 | 
			
		||||
            // no check for failure should have
 | 
			
		||||
| 
						 | 
				
			
			@ -450,7 +515,8 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
 | 
			
		|||
 | 
			
		||||
        }
 | 
			
		||||
        memcpy(current_global_prefix, global_prefix, 8);
 | 
			
		||||
        rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
 | 
			
		||||
        ws_bbr_rpl_version_increase(cur);
 | 
			
		||||
 | 
			
		||||
        nd_proxy_downstream_interface_register(cur->id, ws_border_router_proxy_validate, ws_border_router_proxy_state_update);
 | 
			
		||||
    } else if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) {
 | 
			
		||||
        /*
 | 
			
		||||
| 
						 | 
				
			
			@ -511,7 +577,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
 | 
			
		|||
        if (cur->ws_info->pan_version_timer > seconds) {
 | 
			
		||||
            cur->ws_info->pan_version_timer -= seconds;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Border router has timed out
 | 
			
		||||
            // PAN version number update
 | 
			
		||||
            tr_debug("Border router version number update");
 | 
			
		||||
            cur->ws_info->pan_version_timer = ws_common_version_lifetime_get(cur->ws_info->network_size_config);
 | 
			
		||||
            cur->ws_info->pan_information.pan_version++;
 | 
			
		||||
| 
						 | 
				
			
			@ -522,9 +588,13 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
 | 
			
		|||
                ws_common_network_size_configure(cur, cur->ws_info->pan_information.pan_size);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cur->ws_info->rpl_version_timer > seconds) {
 | 
			
		||||
            cur->ws_info->rpl_version_timer -= seconds;
 | 
			
		||||
        } else {
 | 
			
		||||
            // RPL version update needed
 | 
			
		||||
            ws_bbr_rpl_version_increase(cur);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t test_pan_size_override = 0xffff;
 | 
			
		||||
| 
						 | 
				
			
			@ -607,15 +677,11 @@ void ws_bbr_stop(int8_t interface_id)
 | 
			
		|||
{
 | 
			
		||||
#ifdef HAVE_WS_BORDER_ROUTER
 | 
			
		||||
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
 | 
			
		||||
 | 
			
		||||
    ws_bbr_routing_stop(cur);
 | 
			
		||||
 | 
			
		||||
    backbone_interface_id = -1;
 | 
			
		||||
 | 
			
		||||
    if (!protocol_6lowpan_rpl_domain) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
 | 
			
		||||
    protocol_6lowpan_rpl_root_dodag = NULL;
 | 
			
		||||
    current_instance_id++;
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -626,11 +692,12 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options)
 | 
			
		|||
{
 | 
			
		||||
#ifdef HAVE_WS_BORDER_ROUTER
 | 
			
		||||
 | 
			
		||||
    (void)interface_id;
 | 
			
		||||
    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_rpl_root_stop();
 | 
			
		||||
        ws_bbr_routing_stop(cur);
 | 
			
		||||
    }
 | 
			
		||||
    configuration = options;
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
 | 
			
		|||
 | 
			
		||||
uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur);
 | 
			
		||||
 | 
			
		||||
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase);
 | 
			
		||||
void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase);
 | 
			
		||||
 | 
			
		||||
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
 | 
			
		|||
 | 
			
		||||
#define ws_bbr_seconds_timer( cur, seconds)
 | 
			
		||||
#define ws_bbr_pan_size(cur) 0
 | 
			
		||||
#define ws_bbr_rpl_config( imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase)
 | 
			
		||||
#define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase)
 | 
			
		||||
#define ws_bbr_ready_to_start(cur) true
 | 
			
		||||
 | 
			
		||||
#endif //HAVE_WS_BORDER_ROUTER
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,6 @@ static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *
 | 
			
		|||
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
 | 
			
		||||
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
 | 
			
		||||
static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data);
 | 
			
		||||
static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur);
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +201,7 @@ static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur)
 | 
			
		|||
{
 | 
			
		||||
    if (cur->bootStrapId < 0) {
 | 
			
		||||
        cur->bootStrapId = eventOS_event_handler_create(&ws_bootstrap_event_handler, WS_INIT_EVENT);
 | 
			
		||||
        tr_debug("WS tasklet init");
 | 
			
		||||
        tr_info("WS tasklet init");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cur->bootStrapId < 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -321,12 +320,16 @@ static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighb
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor)
 | 
			
		||||
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];
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
    buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL);
 | 
			
		||||
    if (buffer) {
 | 
			
		||||
        protocol_push(buffer);
 | 
			
		||||
| 
						 | 
				
			
			@ -368,7 +371,7 @@ void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks)
 | 
			
		|||
 | 
			
		||||
            } else {
 | 
			
		||||
                //Random TX wait period is over
 | 
			
		||||
                entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info);
 | 
			
		||||
                entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info, entry->nud_process);
 | 
			
		||||
                if (!entry->wait_response) {
 | 
			
		||||
                    if (entry->nud_process && entry->retry_count < 2) {
 | 
			
		||||
                        entry->timer = randLIB_get_random_in_range(1, 900);
 | 
			
		||||
| 
						 | 
				
			
			@ -409,7 +412,8 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry
 | 
			
		|||
    memcpy(cur->ws_info->hopping_schdule.channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8);
 | 
			
		||||
    cur->ws_info->hopping_schdule.uc_fixed_channel = fhss_configuration->unicast_fixed_channel;
 | 
			
		||||
    cur->ws_info->hopping_schdule.bc_fixed_channel = fhss_configuration->broadcast_fixed_channel;
 | 
			
		||||
    cur->ws_info->hopping_schdule.uc_channel_function = fhss_configuration->ws_uc_channel_function;
 | 
			
		||||
    // Read UC channel function from WS info because FHSS might be temporarily configured to fixed channel during discovery.
 | 
			
		||||
    cur->ws_info->hopping_schdule.uc_channel_function = cur->ws_info->fhss_uc_channel_function;
 | 
			
		||||
    cur->ws_info->hopping_schdule.bc_channel_function = fhss_configuration->ws_bc_channel_function;
 | 
			
		||||
    cur->ws_info->hopping_schdule.fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval;
 | 
			
		||||
    cur->ws_info->hopping_schdule.fhss_broadcast_interval = fhss_configuration->fhss_broadcast_interval;
 | 
			
		||||
| 
						 | 
				
			
			@ -420,8 +424,7 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry
 | 
			
		|||
static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
 | 
			
		||||
{
 | 
			
		||||
    fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
 | 
			
		||||
 | 
			
		||||
    if (!fhss_api || (fhss_api && cur->ws_info->fhss_owner)) {
 | 
			
		||||
    if (!fhss_api) {
 | 
			
		||||
        // When FHSS doesn't exist yet, create one
 | 
			
		||||
        fhss_ws_configuration_t fhss_configuration;
 | 
			
		||||
        memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t));
 | 
			
		||||
| 
						 | 
				
			
			@ -437,26 +440,11 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
 | 
			
		|||
        fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function;
 | 
			
		||||
        fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval;
 | 
			
		||||
        fhss_configuration.fhss_broadcast_interval = cur->ws_info->fhss_bc_interval;
 | 
			
		||||
 | 
			
		||||
        if (!fhss_api) {
 | 
			
		||||
        fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
 | 
			
		||||
        if (!fhss_api) {
 | 
			
		||||
                tr_error("fhss create failed");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        ns_sw_mac_fhss_register(cur->mac_api, fhss_api);
 | 
			
		||||
            cur->ws_info->fhss_owner = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            //Configuration set
 | 
			
		||||
            ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
 | 
			
		||||
 | 
			
		||||
            if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
                ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Clear OWN HOP
 | 
			
		||||
                ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Read defaults from the configuration to help FHSS testing
 | 
			
		||||
        const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(fhss_api);
 | 
			
		||||
| 
						 | 
				
			
			@ -519,7 +507,7 @@ static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, ui
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
 | 
			
		||||
static int8_t ws_fhss_configure(protocol_interface_info_entry_t *cur, bool discovery)
 | 
			
		||||
{
 | 
			
		||||
    // Read configuration of existing FHSS and start using the default values for any network
 | 
			
		||||
    fhss_ws_configuration_t fhss_configuration;
 | 
			
		||||
| 
						 | 
				
			
			@ -528,8 +516,12 @@ static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) {
 | 
			
		||||
        memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Discovery is done using fixed channel
 | 
			
		||||
    if (discovery) {
 | 
			
		||||
        fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL;
 | 
			
		||||
    } else {
 | 
			
		||||
        fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_uc_channel_function;
 | 
			
		||||
    }
 | 
			
		||||
    fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL;
 | 
			
		||||
    fhss_configuration.fhss_broadcast_interval = 0;
 | 
			
		||||
    uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
 | 
			
		||||
| 
						 | 
				
			
			@ -641,8 +633,9 @@ static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entr
 | 
			
		|||
        mac64[0] |= 2; //Set Local Bit
 | 
			
		||||
        mac64[0] &= ~1; //Clear multicast bit
 | 
			
		||||
 | 
			
		||||
        tr_info("Generated random MAC %s", trace_array(mac64, 8));
 | 
			
		||||
        tr_info("Generated random MAC address");
 | 
			
		||||
    }
 | 
			
		||||
    tr_info("MAC address: %s", trace_array(mac64, 8));
 | 
			
		||||
    mac_helper_mac64_set(cur, mac64);
 | 
			
		||||
 | 
			
		||||
    memcpy(cur->iid_eui64, mac64, 8);
 | 
			
		||||
| 
						 | 
				
			
			@ -660,7 +653,6 @@ static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entr
 | 
			
		|||
uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr_type, const uint8_t *addr_ptr)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    uint16_t etx;
 | 
			
		||||
    if (!addr_ptr || !interface) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -675,42 +667,11 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
 | 
			
		|||
    ws_neighbor_class_entry_t *ws_neighbour = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, attribute_index);
 | 
			
		||||
    etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, attribute_index);
 | 
			
		||||
 | 
			
		||||
    if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
    if (!ws_neighbour || !etx_entry) {
 | 
			
		||||
        return 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
        if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 /*||
 | 
			
		||||
                !ws_neighbour->candidate_parent*/) {
 | 
			
		||||
            // if RSL value is not good enough candidate parent flag is removed and device not accepted as parent
 | 
			
		||||
            //tr_debug("ws_etx_read not valid params");
 | 
			
		||||
            return 0xffff;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //If we are not following gbobal Broadcast synch
 | 
			
		||||
        if (!interface->ws_info->pan_information.use_parent_bs) {
 | 
			
		||||
            //We must know both information's here
 | 
			
		||||
            if (!ws_neighbour->broadcast_shedule_info_stored ||
 | 
			
		||||
                    !ws_neighbour->broadcast_timing_info_stored) {
 | 
			
		||||
                return 0xffff;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!ws_neighbour->broadcast_timing_info_stored) {
 | 
			
		||||
                //Global shedule is stored already
 | 
			
		||||
                tr_debug("ws_etx_read not valid NO BTI");
 | 
			
		||||
                return 0xffff;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    etx = etx_local_etx_read(interface->id, attribute_index);
 | 
			
		||||
    if (etx == 0) {
 | 
			
		||||
        return 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //tr_debug("ws_etx_read etx:%d", etx);
 | 
			
		||||
    return etx;
 | 
			
		||||
    return etx_local_etx_read(interface->id, attribute_index);
 | 
			
		||||
}
 | 
			
		||||
bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry,  bool unicast, uint8_t seq)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -759,6 +720,8 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
 | 
			
		|||
        goto cleanup;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Wi-sun will trig event for stamechine this timer must be zero on init */
 | 
			
		||||
    cur->bootsrap_state_machine_cnt = 0;
 | 
			
		||||
    /* Disable SLLAO send/mandatory receive with the ARO */
 | 
			
		||||
    cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true;
 | 
			
		||||
    /* Omit sending of NA if ARO SUCCESS */
 | 
			
		||||
| 
						 | 
				
			
			@ -803,8 +766,12 @@ static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur)
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tr_debug("Wi-SUN ifdown");
 | 
			
		||||
 | 
			
		||||
    tr_info("Wi-SUN ifdown");
 | 
			
		||||
    // Reset MAC for safe upper layer memory free
 | 
			
		||||
    protocol_mac_reset(cur);
 | 
			
		||||
    ns_sw_mac_fhss_unregister(cur->mac_api);
 | 
			
		||||
    ns_fhss_delete(cur->ws_info->fhss_api);
 | 
			
		||||
    cur->ws_info->fhss_api = NULL;
 | 
			
		||||
    // Reset WS information
 | 
			
		||||
    // ws_common_reset(cur)
 | 
			
		||||
    ws_llc_reset(cur);
 | 
			
		||||
| 
						 | 
				
			
			@ -862,19 +829,26 @@ void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur)
 | 
			
		|||
 | 
			
		||||
static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr)
 | 
			
		||||
{
 | 
			
		||||
    ws_wp_network_name_t network_name;
 | 
			
		||||
 | 
			
		||||
    if (!network_name_ptr || !ie_ext) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_wp_network_name_t network_name;
 | 
			
		||||
    if (!ws_wp_nested_network_name_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &network_name)) {
 | 
			
		||||
        tr_warn("No network name IE");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (network_name_ptr == NULL || strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) {
 | 
			
		||||
    if (network_name.network_name_length != strlen(network_name_ptr)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // names have equal length and same characters
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -894,10 +868,15 @@ static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interf
 | 
			
		|||
     * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
        //Border router never set consistent that will guarantee that BR will send advertisment
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef WISUN_1_0_ERRATA_FIX
 | 
			
		||||
    // All messages are considered as consistent only Solicit will cause inconsistent
 | 
			
		||||
    if (pan_information->pan_size == cur->ws_info->pan_information.pan_size) {
 | 
			
		||||
        //If same pan size information then set consistent value
 | 
			
		||||
        trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    // Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements
 | 
			
		||||
    if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1460,8 +1439,13 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c
 | 
			
		|||
static void ws_bootstrap_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message)
 | 
			
		||||
{
 | 
			
		||||
    ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1);
 | 
			
		||||
    (void)interface;
 | 
			
		||||
    (void)asynch_message;
 | 
			
		||||
    if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
        if (asynch_message == WS_FT_PAN_CONF && interface->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ACTIVATE) {
 | 
			
		||||
            interface->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
 | 
			
		||||
            tr_info("Activate new default key %u", interface->ws_info->pending_key_index_info.index + 1);
 | 
			
		||||
            mac_helper_security_auto_request_key_index_set(interface, interface->ws_info->pending_key_index_info.index, interface->ws_info->pending_key_index_info.index + 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t ws_time_from_last_unicast_traffic(uint32_t current_time_stamp, ws_neighbor_class_entry_t *ws_neighbor)
 | 
			
		||||
| 
						 | 
				
			
			@ -1495,7 +1479,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
 | 
			
		|||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cur->nud_active || ws_neighbor->accelerated_etx_probe || ws_neighbor->negative_aro_send) {
 | 
			
		||||
        if (cur->nud_active || ws_neighbor->negative_aro_send) {
 | 
			
		||||
            //If NUD process is active do not trig
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1589,30 +1573,11 @@ static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_en
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t parent_candidate_size = rpl_control_parent_candidate_list_size(interface, false);
 | 
			
		||||
    //TODO check bootstarap state for review
 | 
			
		||||
    //if we have enough candidates at list do not accept new multicast neighbours
 | 
			
		||||
    if (parent_candidate_size > interface->ws_info->rpl_parent_candidate_max) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    parent_candidate_size = rpl_control_parent_candidate_list_size(interface, true);
 | 
			
		||||
    //If we have already enough parent selected Candidates count is bigger than configured
 | 
			
		||||
    if (parent_candidate_size >= interface->ws_info->rpl_selected_parent_max) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protocol_interface_info_entry_t *cur = user_data;
 | 
			
		||||
    lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr);
 | 
			
		||||
    lowpan_adaptation_neigh_remove_free_tx_tables(cur, entry_ptr);
 | 
			
		||||
    // Sleepy host
 | 
			
		||||
    if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
 | 
			
		||||
        mac_data_poll_protocol_poll_mode_decrement(cur);
 | 
			
		||||
| 
						 | 
				
			
			@ -1634,6 +1599,8 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt
 | 
			
		|||
static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t time_from_start = entry_ptr->link_lifetime - entry_ptr->lifetime;
 | 
			
		||||
    uint8_t ll_address[16];
 | 
			
		||||
    bool nud_proces = false;
 | 
			
		||||
    bool activate_nud = false;
 | 
			
		||||
    protocol_interface_info_entry_t *cur = user_data;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1644,17 +1611,22 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t ll_address[16];
 | 
			
		||||
    ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
 | 
			
		||||
 | 
			
		||||
    if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) {
 | 
			
		||||
 | 
			
		||||
        ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
 | 
			
		||||
 | 
			
		||||
        if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
 | 
			
		||||
            if (!ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) {
 | 
			
		||||
                //NUD Not needed for if neighbour is not child or parent candidate
 | 
			
		||||
        if (ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) {
 | 
			
		||||
            // This is our child with valid ARO registration Change link timeout to future we check at 2 minute intervals
 | 
			
		||||
            entry_ptr->lifetime = entry_ptr->lifetime + 120;
 | 
			
		||||
            if (entry_ptr->lifetime > entry_ptr->link_lifetime) {
 | 
			
		||||
                entry_ptr->lifetime = entry_ptr->link_lifetime;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
 | 
			
		||||
            //NUD Not needed for if neighbour is not parent candidate
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1666,21 +1638,18 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
 | 
			
		|||
                activate_nud = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if (etx_entry->etx_samples < WS_NEIGBOR_ETX_SAMPLE_MAX) {
 | 
			
		||||
        nud_proces = activate_nud;
 | 
			
		||||
    } else if (etx_entry->etx_samples < WS_NEIGHBOR_ETX_SAMPLE_MAX) {
 | 
			
		||||
        //Take Random number for trig a prope.
 | 
			
		||||
        //ETX Sample 0: random 1-8
 | 
			
		||||
        //ETX Sample 1: random 2-16
 | 
			
		||||
        //ETX Sample 2: random 4-32
 | 
			
		||||
        if (etx_entry->etx_samples == 0 && ws_neighbor->accelerated_etx_probe) {
 | 
			
		||||
            //Accept quick Probe for init ETX
 | 
			
		||||
            activate_nud = true;
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
        ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
 | 
			
		||||
            if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
 | 
			
		||||
        if (!rpl_control_probe_parent_candidate(cur, ll_address)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples;
 | 
			
		||||
        uint32_t time_block = 1 << etx_entry->etx_samples;
 | 
			
		||||
        if (time_from_start >= probe_period) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1695,7 +1664,6 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!activate_nud) {
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1706,14 +1674,9 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    entry->neighbor_info = entry_ptr;
 | 
			
		||||
    if (ws_neighbor->accelerated_etx_probe) {
 | 
			
		||||
        ws_neighbor->accelerated_etx_probe = false;
 | 
			
		||||
        entry->timer = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (etx_entry->etx_samples >= WS_NEIGBOR_ETX_SAMPLE_MAX) {
 | 
			
		||||
        entry->nud_process = true;
 | 
			
		||||
    }
 | 
			
		||||
    entry->nud_process = nud_proces;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1746,12 +1709,13 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
 | 
			
		|||
    if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT)) {
 | 
			
		||||
    if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT, WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT)) {
 | 
			
		||||
        etx_storage_list_allocate(cur->id, 0);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    etx_max_update_set(WS_ETX_MAX_UPDATE);
 | 
			
		||||
    etx_max_set(WS_ETX_MAX);
 | 
			
		||||
 | 
			
		||||
    if (blacklist_init() != 0) {
 | 
			
		||||
        tr_err("MLE blacklist init failed.");
 | 
			
		||||
| 
						 | 
				
			
			@ -2148,7 +2112,22 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle)
 | 
			
		||||
static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance)
 | 
			
		||||
{
 | 
			
		||||
    //Already many candidates
 | 
			
		||||
    if (rpl_control_candidate_list_size(cur, instance) > cur->ws_info->rpl_parent_candidate_max) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Already enough selected candidates
 | 
			
		||||
    if (rpl_control_selected_parent_count(cur, instance) >= cur->ws_info->rpl_selected_parent_max) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protocol_interface_info_entry_t *cur = handle;
 | 
			
		||||
| 
						 | 
				
			
			@ -2156,26 +2135,102 @@ static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handl
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t mac64[8];
 | 
			
		||||
    if (blacklist_reject(ll_parent_address)) {
 | 
			
		||||
        // Rejected by blacklist
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t mac64[10];
 | 
			
		||||
    //bool replace_ok = false;
 | 
			
		||||
    //bool create_ok = false;
 | 
			
		||||
    llc_neighbour_req_t neigh_buffer;
 | 
			
		||||
 | 
			
		||||
    //Discover neigh ready here for possible ETX validate
 | 
			
		||||
    memcpy(mac64, ll_parent_address + 8, 8);
 | 
			
		||||
    mac64[0] ^= 2;
 | 
			
		||||
    llc_neighbour_req_t neigh_buffer;
 | 
			
		||||
    if (ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false)) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false);
 | 
			
		||||
    //Discover Multicast temporary entry for create neighbour table entry for new candidate
 | 
			
		||||
    ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64);
 | 
			
		||||
 | 
			
		||||
    if (!ws_rpl_candidate_soft_filtering(cur, instance)) {
 | 
			
		||||
        if (!neigh_buffer.neighbor) {
 | 
			
		||||
            //Do not accept any new in that Place
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint8_t replacing[16];
 | 
			
		||||
        //Accept Know neighbour if it is enough good
 | 
			
		||||
        if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        // +2 Is for PAN ID space
 | 
			
		||||
        memcpy(mac64 + 2, replacing + 8, 8);
 | 
			
		||||
        mac64[2] ^= 2;
 | 
			
		||||
 | 
			
		||||
        if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) {
 | 
			
		||||
            //Not proped yet because ETX is 0xffff
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint16_t etx = 0;
 | 
			
		||||
        if (neigh_buffer.neighbor) {
 | 
			
		||||
            etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Accept now only better one's when max candidates selected and max candidate list size is reached
 | 
			
		||||
        return rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Neighbour allready
 | 
			
		||||
    if (neigh_buffer.neighbor) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!ws_rpl_dio_new_parent_accept(cur)) {
 | 
			
		||||
#if 0
 | 
			
		||||
    if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Discover Multicast temporary entry
 | 
			
		||||
    // +2 Is for PAN ID space
 | 
			
		||||
    memcpy(mac64 + 2, replacing + 8, 8);
 | 
			
		||||
    mac64[2] ^= 2;
 | 
			
		||||
 | 
			
		||||
    if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) {
 | 
			
		||||
        //Not proped yet because ETX is 0xffff
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t etx = 0;
 | 
			
		||||
    if (neigh_buffer.neighbor) {
 | 
			
		||||
        etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Accept now only better one's when max candidates selected and max candidate list size is reached
 | 
			
		||||
    if (!rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    //TODO if replacing has poor ETX, put it in blacklist as "poor ETX" to prevent reselection
 | 
			
		||||
    //Mark That We can try remove replaced link
 | 
			
		||||
    replace_ok = true;
 | 
			
		||||
 | 
			
		||||
neigh_create:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (neigh_buffer.neighbor) {
 | 
			
		||||
        //Use Already discovered entry
 | 
			
		||||
        create_ok = true;
 | 
			
		||||
        goto neigh_create_ok;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64);
 | 
			
		||||
    if (!entry) {
 | 
			
		||||
        //No Multicast Entry Available
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Create entry
 | 
			
		||||
    bool create_ok = ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, true);
 | 
			
		||||
    bool create_ok = ws_bootstrap_neighbor_info_request(cur, entry->mac64, &neigh_buffer, true);
 | 
			
		||||
    if (create_ok) {
 | 
			
		||||
        ws_neighbor_class_entry_t *ws_neigh = neigh_buffer.ws_neighbor;
 | 
			
		||||
        //Copy fhss temporary data
 | 
			
		||||
| 
						 | 
				
			
			@ -2186,7 +2241,15 @@ static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handl
 | 
			
		|||
    }
 | 
			
		||||
    ws_llc_free_multicast_temp_entry(cur, entry);
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
neigh_create_ok:
 | 
			
		||||
 | 
			
		||||
    if (create_ok && replace_ok) {
 | 
			
		||||
        //Try remove here when accepted new better one possible
 | 
			
		||||
        tr_debug("Remove %s by %s", trace_ipv6(replacing), trace_ipv6(ll_parent_address));
 | 
			
		||||
        rpl_control_neighbor_delete_from_instance(cur, instance, replacing);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return create_ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2198,13 +2261,18 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur)
 | 
			
		|||
 | 
			
		||||
    addr_add_router_groups(cur);
 | 
			
		||||
    rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, downstream);
 | 
			
		||||
    rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback_t, cur);
 | 
			
		||||
    rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback, cur);
 | 
			
		||||
    // If i am router I Do this
 | 
			
		||||
    rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf);
 | 
			
		||||
    rpl_control_process_routes(protocol_6lowpan_rpl_domain, false); // Wi-SUN assumes that no default route needed
 | 
			
		||||
    rpl_control_request_parent_link_confirmation(true);
 | 
			
		||||
    rpl_control_set_dio_multicast_min_config_advertisment_count(WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT);
 | 
			
		||||
    rpl_control_set_dao_retry_count(WS_MAX_DAO_RETRIES);
 | 
			
		||||
    rpl_control_set_initial_dao_ack_wait(WS_MAX_DAO_INITIAL_TIMEOUT);
 | 
			
		||||
    rpl_control_set_mrhof_parent_set_size(WS_MAX_PARENT_SET_COUNT);
 | 
			
		||||
    if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
        rpl_control_set_memory_limits(WS_NODE_RPL_SOFT_MEM_LIMIT, WS_NODE_RPL_HARD_MEM_LIMIT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2222,7 +2290,7 @@ static void ws_bootstrap_network_discovery_configure(protocol_interface_info_ent
 | 
			
		|||
    cur->ws_info->network_pan_id = 0xffff;
 | 
			
		||||
 | 
			
		||||
    ws_common_regulatory_domain_config(cur);
 | 
			
		||||
    ws_fhss_discovery_configure(cur);
 | 
			
		||||
    ws_fhss_configure(cur, true);
 | 
			
		||||
 | 
			
		||||
    //Set Network names, Pan information configure, hopping schedule & GTKHash
 | 
			
		||||
    ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name));
 | 
			
		||||
| 
						 | 
				
			
			@ -2324,7 +2392,16 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint
 | 
			
		|||
 | 
			
		||||
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index)
 | 
			
		||||
{
 | 
			
		||||
    // Set send key
 | 
			
		||||
 | 
			
		||||
    if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
        if (cur->mac_parameters->mac_default_key_index != 0 && cur->mac_parameters->mac_default_key_index  != index + 1) {
 | 
			
		||||
            tr_info("New Pending key Request %u", index + 1);
 | 
			
		||||
            cur->ws_info->pending_key_index_info.state = PENDING_KEY_INDEX_ADVERTISMENT;
 | 
			
		||||
            cur->ws_info->pending_key_index_info.index = index;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mac_helper_security_auto_request_key_index_set(cur, index, index + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2377,6 +2454,8 @@ static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry
 | 
			
		|||
    ws_bootstrap_ip_stack_reset(cur);
 | 
			
		||||
 | 
			
		||||
    cur->ws_info->pas_requests = 0;
 | 
			
		||||
    //Calculate max time for config learn state
 | 
			
		||||
    cur->ws_info->pan_config_sol_max_timeout = trickle_timer_max(&cur->ws_info->trickle_params_pan_discovery, PCS_MAX);
 | 
			
		||||
    // Reset advertisement solicit trickle to start discovering network
 | 
			
		||||
    cur->ws_info->trickle_pcs_running = true;
 | 
			
		||||
    trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery);
 | 
			
		||||
| 
						 | 
				
			
			@ -2387,8 +2466,11 @@ 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->network_size_config == NETWORK_SIZE_LARGE || cur->ws_info->network_size_config == NETWORK_SIZE_MEDIUM) {
 | 
			
		||||
        // 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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -2494,13 +2576,11 @@ static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entr
 | 
			
		|||
 | 
			
		||||
    uint16_t etx = etx_local_etx_read(cur->id, mac_neighbor->index);
 | 
			
		||||
    if (etx == 0) {
 | 
			
		||||
        etx = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
    if (etx > 0x800) {
 | 
			
		||||
        // Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0.
 | 
			
		||||
        etx = 0x800;
 | 
			
		||||
    }
 | 
			
		||||
        etx = WS_ETX_MAX; //SET maxium value here if ETX is unknown
 | 
			
		||||
    } else {
 | 
			
		||||
        //Scale to 128 based ETX (local read retur 0x100 - 0xffff
 | 
			
		||||
        etx = etx >> 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ws_neighbor->routing_cost + etx;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2574,7 +2654,13 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur)
 | 
			
		|||
 | 
			
		||||
    async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur);
 | 
			
		||||
    async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
 | 
			
		||||
    if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && cur->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ADVERTISMENT) {
 | 
			
		||||
        async_req.security.KeyIndex =  cur->ws_info->pending_key_index_info.index + 1;
 | 
			
		||||
        cur->ws_info->pending_key_index_info.state = PENDING_KEY_INDEX_ACTIVATE;
 | 
			
		||||
    } else {
 | 
			
		||||
        async_req.security.KeyIndex = mac_helper_default_key_index_get(cur);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_llc_asynch_request(cur, &async_req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2594,6 +2680,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
 | 
			
		|||
            break;
 | 
			
		||||
        case WS_DISCOVERY_START:
 | 
			
		||||
            tr_info("Discovery start");
 | 
			
		||||
 | 
			
		||||
            //Clear Pending Key Index State
 | 
			
		||||
            cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
 | 
			
		||||
            cur->mac_parameters->mac_default_key_index = 0;
 | 
			
		||||
 | 
			
		||||
            // All trickle timers stopped to allow entry from any state
 | 
			
		||||
            cur->ws_info->trickle_pa_running = false;
 | 
			
		||||
            cur->ws_info->trickle_pc_running = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -2601,7 +2692,7 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
 | 
			
		|||
            cur->ws_info->trickle_pcs_running = false;
 | 
			
		||||
 | 
			
		||||
            if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
 | 
			
		||||
                tr_debug("Border router start network");
 | 
			
		||||
                tr_info("Border router start network");
 | 
			
		||||
 | 
			
		||||
                if (!ws_bbr_ready_to_start(cur)) {
 | 
			
		||||
                    // Wi-SUN not started yet we wait for Border router permission
 | 
			
		||||
| 
						 | 
				
			
			@ -2722,9 +2813,14 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur)
 | 
			
		|||
 | 
			
		||||
    tr_debug("analyze network discovery result");
 | 
			
		||||
 | 
			
		||||
select_best_candidate:
 | 
			
		||||
    selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur);
 | 
			
		||||
 | 
			
		||||
    if (!selected_parent_ptr) {
 | 
			
		||||
        // Configure LLC for network discovery
 | 
			
		||||
        ws_bootstrap_network_discovery_configure(cur);
 | 
			
		||||
        // randomize new channel and start MAC
 | 
			
		||||
        ws_bootstrap_fhss_activate(cur);
 | 
			
		||||
        // Next check will be after one trickle
 | 
			
		||||
        cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
 | 
			
		||||
        tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
 | 
			
		||||
| 
						 | 
				
			
			@ -2740,7 +2836,10 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    ws_bootstrap_fhss_activate(cur);
 | 
			
		||||
    llc_neighbour_req_t neighbor_info;
 | 
			
		||||
    if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) {
 | 
			
		||||
        return;
 | 
			
		||||
        //Remove Neighbour and set Link setup back
 | 
			
		||||
        ns_list_remove(&cur->ws_info->parent_list_reserved, selected_parent_ptr);
 | 
			
		||||
        ns_list_add_to_end(&cur->ws_info->parent_list_free, selected_parent_ptr);
 | 
			
		||||
        goto select_best_candidate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp);
 | 
			
		||||
| 
						 | 
				
			
			@ -2848,7 +2947,7 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
 | 
			
		|||
            cur->ws_info->trickle_pc_running = false;
 | 
			
		||||
            cur->ws_info->trickle_pas_running = false;
 | 
			
		||||
            cur->ws_info->trickle_pcs_running = false;
 | 
			
		||||
 | 
			
		||||
            ws_fhss_configure(cur, false);
 | 
			
		||||
            ws_bootstrap_start_authentication(cur);
 | 
			
		||||
            break;
 | 
			
		||||
        case ER_RPL_SCAN:
 | 
			
		||||
| 
						 | 
				
			
			@ -2873,20 +2972,34 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t
 | 
			
		|||
        tr_info("Send PAN advertisement Solicit");
 | 
			
		||||
        ws_bootstrap_pan_advert_solicit(cur);
 | 
			
		||||
    }
 | 
			
		||||
    if (cur->ws_info->trickle_pcs_running &&
 | 
			
		||||
            trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
 | 
			
		||||
        // send PAN Configuration solicit
 | 
			
		||||
        if (cur->ws_info->pas_requests >= PCS_MAX) {
 | 
			
		||||
            // if MAX PCS sent restart discovery
 | 
			
		||||
    if (cur->ws_info->trickle_pcs_running) {
 | 
			
		||||
 | 
			
		||||
        //Update MAX config sol timeout timer
 | 
			
		||||
        if (cur->ws_info->pan_config_sol_max_timeout > ticks) {
 | 
			
		||||
            cur->ws_info->pan_config_sol_max_timeout -= ticks;
 | 
			
		||||
        } else {
 | 
			
		||||
            //Config sol state timeout
 | 
			
		||||
            cur->ws_info->pan_config_sol_max_timeout = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
 | 
			
		||||
            if (cur->ws_info->pas_requests < PCS_MAX) {
 | 
			
		||||
                // send PAN Configuration solicit
 | 
			
		||||
                tr_info("Send PAN configuration Solicit");
 | 
			
		||||
                ws_bootstrap_pan_config_solicit(cur);
 | 
			
		||||
            }
 | 
			
		||||
            //Update counter every time reason that we detect PCS_MAX higher state
 | 
			
		||||
            cur->ws_info->pas_requests++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cur->ws_info->pas_requests > PCS_MAX || cur->ws_info->pan_config_sol_max_timeout == 0) {
 | 
			
		||||
            // if MAX PCS sent or max waited timeout restart discovery
 | 
			
		||||
            // Trickle is reseted when entering to discovery from state 3
 | 
			
		||||
            tr_info("PAN configuration Solicit timeout");
 | 
			
		||||
            trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
 | 
			
		||||
            ws_bootstrap_event_discovery_start(cur);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        tr_info("Send PAN configuration Solicit");
 | 
			
		||||
        cur->ws_info->pas_requests++;
 | 
			
		||||
        ws_bootstrap_pan_config_solicit(cur);
 | 
			
		||||
    }
 | 
			
		||||
    if (cur->ws_info->trickle_pa_running &&
 | 
			
		||||
            trickle_timer(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2943,23 +3056,4 @@ void ws_secondary_parent_update(protocol_interface_info_entry_t *interface)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_bootstrap_etx_accelerate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh)
 | 
			
		||||
{
 | 
			
		||||
    ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neigh->index);
 | 
			
		||||
    //Enable Faster ETX probing
 | 
			
		||||
    ws_neighbor->accelerated_etx_probe = true;
 | 
			
		||||
    //Move Neighbor to first to for accelerate Process
 | 
			
		||||
    mac_neighbor_table_t *table_class = mac_neighbor_info(interface);
 | 
			
		||||
    ns_list_remove(&table_class->neighbour_list, neigh);
 | 
			
		||||
    ns_list_add_to_start(&table_class->neighbour_list, neigh);
 | 
			
		||||
    //Try to Generate Active NUD Immediately
 | 
			
		||||
    if (!ws_neighbor_entry_nud_notify(neigh, interface)) {
 | 
			
		||||
        return;//Return if NUD active is full
 | 
			
		||||
    }
 | 
			
		||||
    table_class->active_nud_process++;
 | 
			
		||||
    neigh->nud_active = true;
 | 
			
		||||
    //Push NS to send
 | 
			
		||||
    ws_nud_active_timer(interface, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //HAVE_WS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,8 +76,6 @@ bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur);
 | 
			
		|||
 | 
			
		||||
void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info);
 | 
			
		||||
 | 
			
		||||
void ws_bootstrap_etx_accelerate(struct protocol_interface_info_entry *cur, mac_neighbor_table_entry_t *neigh);
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define ws_bootstrap_init(interface_id, bootstrap_mode) (-1)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +85,6 @@ void ws_bootstrap_etx_accelerate(struct protocol_interface_info_entry *cur, mac_
 | 
			
		|||
#define ws_bootstrap_aro_failure(cur, ll_address)
 | 
			
		||||
#define ws_primary_parent_update(interface, neighbor)
 | 
			
		||||
#define ws_secondary_parent_update(interface)
 | 
			
		||||
#define ws_bootstrap_etx_accelerate(cur, neigh) ((void) 0)
 | 
			
		||||
 | 
			
		||||
#endif //HAVE_WS
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
#include "randLIB.h"
 | 
			
		||||
#include <ns_list.h>
 | 
			
		||||
#include <nsdynmemLIB.h>
 | 
			
		||||
#include "Common_Protocols/icmpv6.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_config.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_common_defines.h"
 | 
			
		||||
#include "6LoWPAN/ws/ws_common.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -316,6 +317,9 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
 | 
			
		|||
    cur->ws_info->fhss_bc_dwell_interval = WS_FHSS_BC_DWELL_INTERVAL;
 | 
			
		||||
    cur->ws_info->fhss_uc_channel_function = WS_DH1CF;
 | 
			
		||||
    cur->ws_info->fhss_bc_channel_function = WS_DH1CF;
 | 
			
		||||
 | 
			
		||||
    cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
 | 
			
		||||
 | 
			
		||||
    for (uint8_t n = 0; n < 8; n++) {
 | 
			
		||||
        cur->ws_info->fhss_channel_mask[n] = 0xffffffff;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -335,11 +339,11 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
 | 
			
		|||
        // doublings:3 (128s)
 | 
			
		||||
        // redundancy; 0 Disabled
 | 
			
		||||
        if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) {
 | 
			
		||||
            ws_bbr_rpl_config(14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
            ws_bbr_rpl_config(cur, 14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        } else if (cur->ws_info->network_size_config == NETWORK_SIZE_CERTIFICATE) {
 | 
			
		||||
            ws_bbr_rpl_config(0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
            ws_bbr_rpl_config(cur, 0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        } else {
 | 
			
		||||
            ws_bbr_rpl_config(0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
            ws_bbr_rpl_config(cur, 0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        }
 | 
			
		||||
        ws_pae_controller_timing_adjust(1); // Fast and reactive network
 | 
			
		||||
    } else if (network_size < 300) {
 | 
			
		||||
| 
						 | 
				
			
			@ -349,7 +353,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
 | 
			
		|||
        // imin: 15 (32s)
 | 
			
		||||
        // doublings:5 (960s)
 | 
			
		||||
        // redundancy; 10
 | 
			
		||||
        ws_bbr_rpl_config(15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        ws_bbr_rpl_config(cur, 15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        ws_pae_controller_timing_adjust(9); // medium limited network
 | 
			
		||||
    } else {
 | 
			
		||||
        // Configure the Wi-SUN discovery trickle parameters
 | 
			
		||||
| 
						 | 
				
			
			@ -358,7 +362,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
 | 
			
		|||
        // imin: 19 (524s, 9 min)
 | 
			
		||||
        // doublings:1 (1048s, 17 min)
 | 
			
		||||
        // redundancy; 10 May need some tuning still
 | 
			
		||||
        ws_bbr_rpl_config(19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        ws_bbr_rpl_config(cur, 19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
 | 
			
		||||
        ws_pae_controller_timing_adjust(24); // Very slow and high latency network
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			@ -387,12 +391,10 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full)
 | 
			
		||||
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));
 | 
			
		||||
    if (cache_full) {
 | 
			
		||||
    blacklist_update(ll_address, false);
 | 
			
		||||
    }
 | 
			
		||||
    ws_bootstrap_aro_failure(cur, ll_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +406,7 @@ void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool 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)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t child_count = 0;
 | 
			
		||||
    uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT;
 | 
			
		||||
| 
						 | 
				
			
			@ -417,13 +419,13 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa
 | 
			
		|||
    //Validate Is EUI64 already allocated for any address
 | 
			
		||||
    if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, eui64)) {
 | 
			
		||||
        tr_info("Child registration from old child");
 | 
			
		||||
        return true;
 | 
			
		||||
        return ARO_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Verify that we have Selected Parent
 | 
			
		||||
    if (interface->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && !rpl_control_parent_candidate_list_size(interface, true)) {
 | 
			
		||||
        tr_info("Do not accept new ARO child: no selected parent");
 | 
			
		||||
        return false;
 | 
			
		||||
        return ARO_TOPOLOGICALLY_INCORRECT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -435,10 +437,10 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa
 | 
			
		|||
    }
 | 
			
		||||
    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 false;
 | 
			
		||||
        return ARO_FULL;
 | 
			
		||||
    }
 | 
			
		||||
    tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size);
 | 
			
		||||
    return true;
 | 
			
		||||
    return ARO_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
 | 
			
		||||
| 
						 | 
				
			
			@ -447,23 +449,13 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con
 | 
			
		|||
    if (!neighbour) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbour->index);
 | 
			
		||||
    ws_neighbor->negative_aro_send = true;
 | 
			
		||||
    neighbour->lifetime = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; //Remove anyway if Packet is freed before MAC push
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh)
 | 
			
		||||
{
 | 
			
		||||
    etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, neigh->index);
 | 
			
		||||
 | 
			
		||||
    if (neigh->nud_active || !neigh->trusted_device || !etx_entry || etx_entry->etx_samples) {
 | 
			
		||||
        return; //Do not trig Second NS if Active NUD already, not trusted or ETX samples already done
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ws_bootstrap_etx_accelerate(interface, neigh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t ws_common_version_lifetime_get(uint8_t config)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t lifetime;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,15 @@ typedef struct ws_nud_table_entry {
 | 
			
		|||
    ns_list_link_t  link;
 | 
			
		||||
} ws_nud_table_entry_t;
 | 
			
		||||
 | 
			
		||||
#define NO_PENDING_PROCESS 0
 | 
			
		||||
#define PENDING_KEY_INDEX_ADVERTISMENT 1
 | 
			
		||||
#define PENDING_KEY_INDEX_ACTIVATE 2
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    unsigned state: 2;
 | 
			
		||||
    uint8_t index;
 | 
			
		||||
} ws_pending_key_index_t;
 | 
			
		||||
 | 
			
		||||
typedef NS_LIST_HEAD(ws_nud_table_entry_t, link) ws_nud_table_list_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ws_info_s {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,15 +88,17 @@ typedef struct ws_info_s {
 | 
			
		|||
    parent_info_t parent_info[WS_PARENT_LIST_SIZE];
 | 
			
		||||
    parent_info_list_t parent_list_free;
 | 
			
		||||
    parent_info_list_t parent_list_reserved;
 | 
			
		||||
    uint32_t pan_version_timer;            /**< border router version udate timeout */
 | 
			
		||||
    uint16_t rpl_version_timer;            /**< RPL version update timeout */
 | 
			
		||||
    uint32_t pan_version_timer;            /**< border router version update timeout */
 | 
			
		||||
    uint32_t pan_version_timeout_timer;    /**< routers will fallback to previous state after this */
 | 
			
		||||
    uint32_t pan_config_sol_max_timeout;
 | 
			
		||||
    uint8_t gtkhash[32];
 | 
			
		||||
    bool configuration_learned: 1;
 | 
			
		||||
    bool trickle_pas_running: 1;
 | 
			
		||||
    bool trickle_pa_running: 1;
 | 
			
		||||
    bool trickle_pcs_running: 1;
 | 
			
		||||
    bool trickle_pc_running: 1;
 | 
			
		||||
    bool fhss_owner: 1;
 | 
			
		||||
    ws_pending_key_index_t pending_key_index_info;
 | 
			
		||||
    // default fhss parameters for this device
 | 
			
		||||
    uint8_t fhss_uc_dwell_interval;
 | 
			
		||||
    uint8_t fhss_bc_dwell_interval;
 | 
			
		||||
| 
						 | 
				
			
			@ -126,13 +137,11 @@ 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_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full);
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
 | 
			
		||||
 | 
			
		||||
void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh);
 | 
			
		||||
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
 | 
			
		||||
 | 
			
		||||
bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -146,11 +155,10 @@ uint32_t ws_common_version_timeout_get(uint8_t config);
 | 
			
		|||
#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_aro_failure(cur, ll_address, cache_full)
 | 
			
		||||
#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) (false)
 | 
			
		||||
#define ws_common_etx_validate(interface, neigh) ((void) 0)
 | 
			
		||||
#define ws_common_allow_child_registration(cur, eui64) (2)
 | 
			
		||||
#define ws_common_negative_aro_mark(interface, eui64)(false)
 | 
			
		||||
 | 
			
		||||
#endif //HAVE_WS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -190,7 +190,8 @@ typedef struct ws_bs_ie {
 | 
			
		|||
#define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260
 | 
			
		||||
#define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2
 | 
			
		||||
 | 
			
		||||
#define WS_NEIGBOR_ETX_SAMPLE_MAX 3
 | 
			
		||||
#define WS_NEIGHBOR_ETX_SAMPLE_MAX 3
 | 
			
		||||
#define WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT 3 //This can't be bigger than WS_NEIGHBOR_ETX_SAMPLE_MAX
 | 
			
		||||
#define WS_NEIGHBOUR_MAX_CANDIDATE_PROBE 5
 | 
			
		||||
 | 
			
		||||
#define WS_PROBE_INIT_BASE_SECONDS 8
 | 
			
		||||
| 
						 | 
				
			
			@ -204,6 +205,7 @@ typedef struct ws_bs_ie {
 | 
			
		|||
#define WS_ETX_MIN_SAMPLE_COUNT 4
 | 
			
		||||
 | 
			
		||||
#define WS_ETX_MAX_UPDATE 1024
 | 
			
		||||
#define WS_ETX_MAX 1024
 | 
			
		||||
 | 
			
		||||
#define WS_ETX_MIN_WAIT_TIME 60
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +213,7 @@ typedef struct ws_bs_ie {
 | 
			
		|||
#define WS_RPL_SELECTED_PARENT_MAX 2
 | 
			
		||||
 | 
			
		||||
#define WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX 8
 | 
			
		||||
#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 3
 | 
			
		||||
#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 4
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Wi-sun spesific non-preferred prefix policy label
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,10 @@
 | 
			
		|||
#define PAN_VERSION_MEDIUM_NETWORK_LIFETIME 15*60
 | 
			
		||||
#define PAN_VERSION_LARGE_NETWORK_LIFETIME 30*60 //30min
 | 
			
		||||
 | 
			
		||||
#define RPL_VERSION_LIFETIME 5*3600
 | 
			
		||||
// RPL version number update intervall
 | 
			
		||||
// after restart version numbers are increased faster and then slowed down when network is stable
 | 
			
		||||
#define RPL_VERSION_LIFETIME 12*3600
 | 
			
		||||
#define RPL_VERSION_LIFETIME_RESTART 3600
 | 
			
		||||
 | 
			
		||||
/* Border router connection lost timeout
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +103,7 @@ extern uint8_t DEVICE_MIN_SENS;
 | 
			
		|||
 | 
			
		||||
#define DATA_MESSAGE_IMIN (10 * 1000)
 | 
			
		||||
#define DATA_MESSAGE_TIMER_EXPIRATIONS 3
 | 
			
		||||
#define DATA_MESSAGE_IMAX (DATA_MESSAGE_IMIN)
 | 
			
		||||
#define DATA_MESSAGE_IMAX (80 * 1000)
 | 
			
		||||
#define MPL_SEED_SET_ENTRY_TIMEOUT (DATA_MESSAGE_IMAX * 24 * 4 / 1000) // 10 seconds per hop making this 240 seconds
 | 
			
		||||
 | 
			
		||||
/* DHCP client timeout configuration values
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +148,11 @@ extern uint8_t DEVICE_MIN_SENS;
 | 
			
		|||
 */
 | 
			
		||||
#define WS_MAX_DAO_RETRIES 3 // With 40s, 80s, 160s, 320s, 640s
 | 
			
		||||
#define WS_MAX_DAO_INITIAL_TIMEOUT 400 // With 40s initial value exponentially increasing
 | 
			
		||||
#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 10 // Define 10 multicast advertisment when learn config or learn config update
 | 
			
		||||
#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 0xff // Advertisment config at every MC DIO
 | 
			
		||||
#define WS_MAX_PARENT_SET_COUNT 2 // maximum amount of parents selected by node
 | 
			
		||||
 | 
			
		||||
#define WS_NODE_RPL_SOFT_MEM_LIMIT 4*1024 // Limit when RPL start purge unused data
 | 
			
		||||
#define WS_NODE_RPL_HARD_MEM_LIMIT 6*1024 // Limit when RPL memory allocation start limit allocation
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Candidate parent list parameters
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -560,7 +560,7 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
 | 
			
		|||
 | 
			
		||||
        if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) {
 | 
			
		||||
            if (!multicast || ws_utt.message_type == WS_FT_EAPOL) {
 | 
			
		||||
                tr_debug("Drop message no neighbor");
 | 
			
		||||
                //tr_debug("Drop message no neighbor");
 | 
			
		||||
                return;
 | 
			
		||||
            } else {
 | 
			
		||||
                //Allocate temporary entry
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -220,20 +220,32 @@ int ws_management_fhss_timing_configure(
 | 
			
		|||
    if (!cur || !ws_info(cur)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (fhss_uc_dwell_interval > 0) {
 | 
			
		||||
 | 
			
		||||
    if (fhss_uc_dwell_interval && fhss_uc_dwell_interval < 15) {
 | 
			
		||||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fhss_bc_dwell_interval && fhss_bc_dwell_interval < 15) {
 | 
			
		||||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool updated_configure = false;
 | 
			
		||||
 | 
			
		||||
    if (fhss_uc_dwell_interval > 0 && cur->ws_info->fhss_uc_dwell_interval != fhss_uc_dwell_interval) {
 | 
			
		||||
        cur->ws_info->fhss_uc_dwell_interval = fhss_uc_dwell_interval;
 | 
			
		||||
        updated_configure = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (fhss_broadcast_interval > 0) {
 | 
			
		||||
    if (fhss_broadcast_interval > 0 && cur->ws_info->fhss_bc_interval != fhss_broadcast_interval) {
 | 
			
		||||
        cur->ws_info->fhss_bc_interval = fhss_broadcast_interval;
 | 
			
		||||
 | 
			
		||||
        updated_configure = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (fhss_bc_dwell_interval > 0) {
 | 
			
		||||
    if (fhss_bc_dwell_interval > 0 && cur->ws_info->fhss_bc_dwell_interval != fhss_bc_dwell_interval) {
 | 
			
		||||
        cur->ws_info->fhss_bc_dwell_interval = fhss_bc_dwell_interval;
 | 
			
		||||
 | 
			
		||||
        updated_configure = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if settings change reset_restart for the settings needed
 | 
			
		||||
    if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
 | 
			
		||||
    if (updated_configure && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
 | 
			
		||||
        // bootstrap active need to restart
 | 
			
		||||
        ws_bootstrap_restart(interface_id);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -259,23 +271,38 @@ int ws_management_fhss_unicast_channel_function_configure(
 | 
			
		|||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dwell_interval && dwell_interval < 15) {
 | 
			
		||||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) {
 | 
			
		||||
        fixed_channel = 0;
 | 
			
		||||
        tr_warn("Fixed channel not configured. Set to 0");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool updated_config = false;
 | 
			
		||||
 | 
			
		||||
    if (cur->ws_info->fhss_uc_channel_function != channel_function) {
 | 
			
		||||
        cur->ws_info->fhss_uc_channel_function = channel_function;
 | 
			
		||||
        updated_config = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) {
 | 
			
		||||
        if (cur->ws_info->fhss_uc_fixed_channel != fixed_channel) {
 | 
			
		||||
            cur->ws_info->fhss_uc_fixed_channel = fixed_channel;
 | 
			
		||||
            updated_config = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        cur->ws_info->fhss_uc_fixed_channel = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dwell_interval && cur->ws_info->fhss_uc_dwell_interval != dwell_interval) {
 | 
			
		||||
        cur->ws_info->fhss_uc_dwell_interval = dwell_interval;
 | 
			
		||||
        updated_config = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if settings change reset_restart for the settings needed
 | 
			
		||||
    if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
 | 
			
		||||
    if (updated_config && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
 | 
			
		||||
        // bootstrap active need to restart
 | 
			
		||||
        ws_bootstrap_restart(interface_id);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -303,23 +330,43 @@ int ws_management_fhss_broadcast_channel_function_configure(
 | 
			
		|||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dwell_interval && dwell_interval < 15) {
 | 
			
		||||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) {
 | 
			
		||||
        fixed_channel = 0;
 | 
			
		||||
        tr_warn("Fixed channel not configured. Set to 0");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool updated_config = false;
 | 
			
		||||
 | 
			
		||||
    if (cur->ws_info->fhss_bc_channel_function != channel_function) {
 | 
			
		||||
        cur->ws_info->fhss_bc_channel_function = channel_function;
 | 
			
		||||
        updated_config = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cur->ws_info->fhss_bc_channel_function == WS_FIXED_CHANNEL) {
 | 
			
		||||
        if (cur->ws_info->fhss_bc_fixed_channel != fixed_channel) {
 | 
			
		||||
            cur->ws_info->fhss_bc_fixed_channel = fixed_channel;
 | 
			
		||||
            updated_config = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        cur->ws_info->fhss_bc_fixed_channel = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dwell_interval > 0 && cur->ws_info->fhss_bc_dwell_interval != dwell_interval) {
 | 
			
		||||
        cur->ws_info->fhss_bc_dwell_interval = dwell_interval;
 | 
			
		||||
        updated_config = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (broadcast_interval > 0 && cur->ws_info->fhss_bc_interval != broadcast_interval) {
 | 
			
		||||
        cur->ws_info->fhss_bc_interval = broadcast_interval;
 | 
			
		||||
        updated_config = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if settings change reset_restart for the settings needed
 | 
			
		||||
    if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
 | 
			
		||||
    if (updated_config && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
 | 
			
		||||
        // bootstrap active need to restart
 | 
			
		||||
        ws_bootstrap_restart(interface_id);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,6 @@ typedef struct ws_neighbor_class_entry {
 | 
			
		|||
    bool broadcast_timing_info_stored: 1;
 | 
			
		||||
    bool broadcast_shedule_info_stored: 1;
 | 
			
		||||
    bool synch_done : 1;
 | 
			
		||||
    bool accelerated_etx_probe : 1;
 | 
			
		||||
    bool negative_aro_send : 1;
 | 
			
		||||
    bool unicast_data_rx : 1;
 | 
			
		||||
} ws_neighbor_class_entry_t;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,9 @@
 | 
			
		|||
   nanostack monitor */
 | 
			
		||||
#define SUPPLICANT_NUMBER_TO_PURGE             5
 | 
			
		||||
 | 
			
		||||
// Short GTK lifetime value, for GTK install check
 | 
			
		||||
#define SHORT_GTK_LIFETIME                     10 * 3600  // 10 hours
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    ns_list_link_t link;                                     /**< Link */
 | 
			
		||||
    kmp_service_t *kmp_service;                              /**< KMP service */
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +116,7 @@ static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e resu
 | 
			
		|||
static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
 | 
			
		||||
static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
 | 
			
		||||
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
 | 
			
		||||
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry);
 | 
			
		||||
static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
 | 
			
		||||
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry);
 | 
			
		||||
static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -666,7 +669,9 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
 | 
			
		|||
        sec_prot_keys_gtk_clear(pae_auth->next_gtks, next_gtk_index);
 | 
			
		||||
        sec_prot_keys_gtk_set(pae_auth->next_gtks, next_gtk_index, gtk_value, 0);
 | 
			
		||||
    } else {
 | 
			
		||||
        do {
 | 
			
		||||
            randLIB_get_n_bytes_random(gtk_value, GTK_LEN);
 | 
			
		||||
        } while (sec_prot_keys_gtk_valid_check(gtk_value) < 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Gets latest installed key lifetime and adds GTK expire offset to it
 | 
			
		||||
| 
						 | 
				
			
			@ -910,7 +915,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
 | 
			
		|||
    supp_entry->retry_ticks = 0;
 | 
			
		||||
 | 
			
		||||
    // Get next protocol based on what keys supplicant has
 | 
			
		||||
    kmp_type_e next_type = ws_pae_auth_next_protocol_get(supp_entry);
 | 
			
		||||
    kmp_type_e next_type = ws_pae_auth_next_protocol_get(pae_auth, supp_entry);
 | 
			
		||||
 | 
			
		||||
    if (next_type == KMP_TYPE_NONE) {
 | 
			
		||||
        // All done
 | 
			
		||||
| 
						 | 
				
			
			@ -969,7 +974,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
 | 
			
		|||
    kmp_api_create_request(new_kmp, next_type, &supp_entry->addr, &supp_entry->sec_keys);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
 | 
			
		||||
static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry)
 | 
			
		||||
{
 | 
			
		||||
    kmp_type_e next_type = KMP_TYPE_NONE;
 | 
			
		||||
    sec_prot_keys_t *sec_keys = &supp_entry->sec_keys;
 | 
			
		||||
| 
						 | 
				
			
			@ -999,10 +1004,23 @@ static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
 | 
			
		|||
 | 
			
		||||
    if (gtk_index >= 0) {
 | 
			
		||||
        if (next_type == KMP_TYPE_NONE && gtk_index >= 0) {
 | 
			
		||||
 | 
			
		||||
            /* Check if the PTK has been already used to install GTK to specific index and if it
 | 
			
		||||
             * has been, trigger 4WH to update also the PTK. This prevents writing multiple
 | 
			
		||||
             * GTK keys to same index using same PTK.
 | 
			
		||||
             */
 | 
			
		||||
            if (pae_auth->timer_settings->gtk_expire_offset > SHORT_GTK_LIFETIME &&
 | 
			
		||||
                    sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_keys, gtk_index)) {
 | 
			
		||||
                // start 4WH towards supplicant
 | 
			
		||||
                next_type = IEEE_802_11_4WH;
 | 
			
		||||
                sec_keys->ptk_mismatch = true;
 | 
			
		||||
                tr_info("PAE start 4WH due to GTK index re-use, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
 | 
			
		||||
            } else {
 | 
			
		||||
                // Update just GTK
 | 
			
		||||
                next_type = IEEE_802_11_GKH;
 | 
			
		||||
                tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(supp_entry->addr.eui_64, 8));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,7 +232,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
 | 
			
		|||
#else
 | 
			
		||||
 | 
			
		||||
#define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, timer_settings) 1
 | 
			
		||||
#define ws_pae_auth_timing_adjust(timing) 1
 | 
			
		||||
#define ws_pae_auth_timing_adjust(timing)
 | 
			
		||||
#define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1
 | 
			
		||||
#define ws_pae_auth_delete NULL
 | 
			
		||||
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set) {(void) hash_set;}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,6 +88,7 @@ typedef struct {
 | 
			
		|||
    bool gtks_set : 1;                                               /**< GTKs are set */
 | 
			
		||||
    bool gtkhash_set : 1;                                            /**< GTK hashes are set */
 | 
			
		||||
    bool key_index_set : 1;                                          /**< NW key index is set */
 | 
			
		||||
    bool frame_counter_read : 1;                                     /**< Frame counters has been read */
 | 
			
		||||
} pae_controller_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +109,7 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
 | 
			
		|||
static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key);
 | 
			
		||||
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index);
 | 
			
		||||
static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name);
 | 
			
		||||
static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold);
 | 
			
		||||
static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
 | 
			
		||||
static void ws_pae_controller_data_init(pae_controller_t *controller);
 | 
			
		||||
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller);
 | 
			
		||||
| 
						 | 
				
			
			@ -363,12 +365,16 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
 | 
			
		|||
            if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) {
 | 
			
		||||
                // Install the new network key derived from GTK and network name (GAK) to MAC
 | 
			
		||||
                controller->nw_key_set(interface_ptr, i, i, gak);
 | 
			
		||||
                tr_info("NW: %s", controller->network_name);
 | 
			
		||||
                tr_info("NW: %s", trace_array((uint8_t *)controller->network_name, 20));
 | 
			
		||||
                tr_info("GTK: %s", trace_array(gtk, 16));
 | 
			
		||||
                tr_info("GAK: %s", trace_array(gak, 16));
 | 
			
		||||
                nw_key[i].installed = true;
 | 
			
		||||
                ret = 0;
 | 
			
		||||
#ifdef EXTRA_DEBUG_INFO
 | 
			
		||||
                tr_info("NW name: %s", controller->network_name);
 | 
			
		||||
                size_t nw_name_len = strlen(controller->network_name);
 | 
			
		||||
                tr_info("NW name: %s", trace_array((uint8_t *)controller->network_name, nw_name_len));
 | 
			
		||||
                tr_info("GTK: %s", trace_array(gtk, 16));
 | 
			
		||||
                tr_info("GAK: %s", trace_array(gak, 16));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                tr_error("GAK generation failed network name: %s", controller->network_name);
 | 
			
		||||
                continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -380,9 +386,11 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
 | 
			
		|||
                // Read current counter from MAC
 | 
			
		||||
                uint32_t curr_frame_counter;
 | 
			
		||||
                controller->nw_frame_counter_read(controller->interface_ptr, &curr_frame_counter, i);
 | 
			
		||||
 | 
			
		||||
                // If stored frame counter is greater than MAC counter
 | 
			
		||||
                if (controller->frame_counters.counter[i].frame_counter > curr_frame_counter) {
 | 
			
		||||
                    tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i, controller->frame_counters.counter[i].frame_counter, curr_frame_counter);
 | 
			
		||||
                    tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i,
 | 
			
		||||
                             controller->frame_counters.counter[i].frame_counter, curr_frame_counter);
 | 
			
		||||
                    curr_frame_counter = controller->frame_counters.counter[i].frame_counter;
 | 
			
		||||
                    // Updates MAC frame counter
 | 
			
		||||
                    controller->nw_frame_counter_set(controller->interface_ptr, curr_frame_counter, i);
 | 
			
		||||
| 
						 | 
				
			
			@ -474,6 +482,16 @@ void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Stores frame counters if incremented by threshold and removes network keys from PAE
 | 
			
		||||
       controller and MAC */
 | 
			
		||||
    ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold)
 | 
			
		||||
{
 | 
			
		||||
    /* Checks if frame counters needs to be stored when keys are removed */
 | 
			
		||||
    ws_pae_controller_frame_counter_store(controller, use_threshold);
 | 
			
		||||
 | 
			
		||||
    tr_info("NW keys remove");
 | 
			
		||||
 | 
			
		||||
    nw_key_t *nw_key = controller->nw_key;
 | 
			
		||||
| 
						 | 
				
			
			@ -589,6 +607,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
 | 
			
		|||
    controller->gtks_set = false;
 | 
			
		||||
    controller->gtkhash_set = false;
 | 
			
		||||
    controller->key_index_set = false;
 | 
			
		||||
    controller->frame_counter_read = false;
 | 
			
		||||
    controller->gtk_index = -1;
 | 
			
		||||
    controller->network_name = NULL;
 | 
			
		||||
    controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -602,6 +621,11 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
 | 
			
		|||
 | 
			
		||||
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
 | 
			
		||||
{
 | 
			
		||||
    if (controller->frame_counter_read) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    controller->frame_counter_read = true;
 | 
			
		||||
 | 
			
		||||
    // Read frame counters
 | 
			
		||||
    if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) {
 | 
			
		||||
        bool updated = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -610,6 +634,8 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
 | 
			
		|||
            if (controller->frame_counters.counter[index].set) {
 | 
			
		||||
                // Increments frame counters
 | 
			
		||||
                controller->frame_counters.counter[index].frame_counter += FRAME_COUNTER_INCREMENT;
 | 
			
		||||
                controller->frame_counters.counter[index].stored_frame_counter =
 | 
			
		||||
                    controller->frame_counters.counter[index].frame_counter;
 | 
			
		||||
 | 
			
		||||
                tr_info("Read frame counter: index %i value %"PRIu32"", index, controller->frame_counters.counter[index].frame_counter);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -620,7 +646,6 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
 | 
			
		|||
            // Writes incremented frame counters
 | 
			
		||||
            ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters);
 | 
			
		||||
            ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer);
 | 
			
		||||
            //ws_pae_controller_frame_counter_write(controller, &controller->frame_counters);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -630,6 +655,7 @@ static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counte
 | 
			
		|||
    for (uint8_t index = 0; index < GTK_NUM; index++) {
 | 
			
		||||
        memset(frame_counters->counter[index].gtk, 0, GTK_LEN);
 | 
			
		||||
        frame_counters->counter[index].frame_counter = 0;
 | 
			
		||||
        frame_counters->counter[index].stored_frame_counter = 0;
 | 
			
		||||
        frame_counters->counter[index].set = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -653,7 +679,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt
 | 
			
		|||
    controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update;
 | 
			
		||||
    controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update;
 | 
			
		||||
 | 
			
		||||
    ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set);
 | 
			
		||||
    ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get);
 | 
			
		||||
 | 
			
		||||
    ws_pae_controller_frame_counter_read(controller);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -689,11 +715,8 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Stores frame counter
 | 
			
		||||
    ws_pae_controller_frame_counter_store(controller, false);
 | 
			
		||||
 | 
			
		||||
    // Removes network keys from PAE controller and MAC
 | 
			
		||||
    ws_pae_controller_nw_keys_remove(interface_ptr);
 | 
			
		||||
    // Stores frame counters and removes network keys from PAE controller and MAC
 | 
			
		||||
    ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, false);
 | 
			
		||||
 | 
			
		||||
    // If PAE has been initialized, deletes it
 | 
			
		||||
    if (controller->pae_delete) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1180,7 +1203,7 @@ int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interf
 | 
			
		|||
    memcpy(controller->gtkhash, gtkhash, 32);
 | 
			
		||||
 | 
			
		||||
    if (controller->pae_gtk_hash_update) {
 | 
			
		||||
        return controller->pae_gtk_hash_update(interface_ptr, gtkhash);
 | 
			
		||||
        return controller->pae_gtk_hash_update(interface_ptr, controller->gtkhash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1241,18 +1264,25 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool
 | 
			
		|||
            // If frame counter for the network key has already been stored
 | 
			
		||||
            if (entry->frame_counters.counter[i].set &&
 | 
			
		||||
                    memcmp(entry->nw_key[i].gtk, entry->frame_counters.counter[i].gtk, GTK_LEN) == 0) {
 | 
			
		||||
 | 
			
		||||
                if (curr_frame_counter > entry->frame_counters.counter[i].frame_counter) {
 | 
			
		||||
                    entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
 | 
			
		||||
                }
 | 
			
		||||
                uint32_t frame_counter = entry->frame_counters.counter[i].frame_counter;
 | 
			
		||||
 | 
			
		||||
                // If threshold check is disabled or frame counter has advanced for the threshold value, stores the new value
 | 
			
		||||
                if (!use_threshold ||
 | 
			
		||||
                        curr_frame_counter > entry->frame_counters.counter[i].frame_counter + FRAME_COUNTER_STORE_THRESHOLD) {
 | 
			
		||||
                    entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
 | 
			
		||||
                        frame_counter > entry->frame_counters.counter[i].stored_frame_counter + FRAME_COUNTER_STORE_THRESHOLD) {
 | 
			
		||||
                    entry->frame_counters.counter[i].stored_frame_counter = frame_counter;
 | 
			
		||||
                    update_needed = true;
 | 
			
		||||
                    tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, curr_frame_counter);
 | 
			
		||||
                    tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, frame_counter);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // For new or modified network keys, stores the frame counter value
 | 
			
		||||
                entry->frame_counters.counter[i].set = true;
 | 
			
		||||
                memcpy(entry->frame_counters.counter[i].gtk, entry->nw_key[i].gtk, GTK_LEN);
 | 
			
		||||
                entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
 | 
			
		||||
                entry->frame_counters.counter[i].stored_frame_counter = curr_frame_counter;
 | 
			
		||||
                update_needed = true;
 | 
			
		||||
                tr_debug("Stored new frame counter: index %i value %"PRIu32"", i, curr_frame_counter);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -291,6 +291,20 @@ void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks)
 | 
			
		|||
    entry->ticks = ticks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_pae_lib_supp_timer_ticks_add(supp_entry_t *entry, uint32_t ticks)
 | 
			
		||||
{
 | 
			
		||||
    entry->ticks += ticks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ws_pae_lib_supp_timer_is_running(supp_entry_t *entry)
 | 
			
		||||
{
 | 
			
		||||
    if (entry->ticks == 0) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry)
 | 
			
		||||
{
 | 
			
		||||
    if (entry->active) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -272,6 +272,25 @@ void ws_pae_lib_supp_delete(supp_entry_t *entry);
 | 
			
		|||
 */
 | 
			
		||||
void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  ws_pae_lib_supp_timer_ticks_add adds supplicant timer ticks
 | 
			
		||||
 *
 | 
			
		||||
 * \param entry supplicant entry
 | 
			
		||||
 * \param ticks ticks
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void ws_pae_lib_supp_timer_ticks_add(supp_entry_t *entry, uint32_t ticks);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  ws_pae_lib_supp_timer_is_running checks whether supplicant timer is running
 | 
			
		||||
 *
 | 
			
		||||
 * \param entry supplicant entry
 | 
			
		||||
 *
 | 
			
		||||
 * \return TRUE timer is running, FALSE timer is not running
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
bool ws_pae_lib_supp_timer_is_running(supp_entry_t *entry);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  ws_pae_lib_supp_list_to_active move supplicant to active supplicants list
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ nvm_tlv_entry_t *ws_pae_buffer_allocate(void)
 | 
			
		|||
 | 
			
		||||
void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    int len;
 | 
			
		||||
    tlv_entry->tag = PAE_NVM_NW_INFO_TAG;
 | 
			
		||||
    tlv_entry->len = PAE_NVM_NW_INFO_LEN;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +66,13 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
 | 
			
		|||
    tlv = common_write_16_bit(pan_id, tlv);
 | 
			
		||||
 | 
			
		||||
    memset(tlv, 0, 33);
 | 
			
		||||
    strncpy((char *)tlv, nw_name, 32);
 | 
			
		||||
    // use strnlen & memset instead of strncpy to avoid gcc warning:
 | 
			
		||||
    // call to __builtin___strncpy_chk will always overflow destination buffer [-Werror]
 | 
			
		||||
    len = strlen(nw_name);
 | 
			
		||||
    if (len > 32) {
 | 
			
		||||
        len = 32;
 | 
			
		||||
    }
 | 
			
		||||
    memcpy((char *)tlv, nw_name, len);
 | 
			
		||||
    tlv += 33;
 | 
			
		||||
 | 
			
		||||
    for (uint8_t i = 0; i < GTK_NUM; i++) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,6 +66,9 @@
 | 
			
		|||
// Wait for re-authentication after GTK update
 | 
			
		||||
#define WAIT_FOR_REAUTHENTICATION_TICKS        120 * 10     // 120 seconds
 | 
			
		||||
 | 
			
		||||
// Ticks added to wait for authenticator timer when authentication protocol is started (e.g. EAP-TLS)
 | 
			
		||||
#define START_AUTHENTICATION_TICKS             5 * 10       // 10 seconds
 | 
			
		||||
 | 
			
		||||
// How many times in maximum stored keys are used for authentication
 | 
			
		||||
#define STORED_KEYS_MAXIMUM_USE_COUNT          1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,9 +91,11 @@ typedef struct {
 | 
			
		|||
    ws_pae_supp_auth_completed *auth_completed;            /**< Authentication completed callback, continue bootstrap */
 | 
			
		||||
    ws_pae_supp_nw_key_insert *nw_key_insert;              /**< Key insert callback */
 | 
			
		||||
    ws_pae_supp_nw_key_index_set *nw_key_index_set;        /**< Key index set callback */
 | 
			
		||||
    ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get;        /**< Get pointer to GTK hash storage callback */
 | 
			
		||||
    supp_entry_t entry;                                    /**< Supplicant data */
 | 
			
		||||
    kmp_addr_t target_addr;                                /**< EAPOL target (parent) address */
 | 
			
		||||
    uint16_t initial_key_timer;                            /**< Timer to trigger initial EAPOL-Key */
 | 
			
		||||
    uint16_t initial_key_retry_timer;                      /**< Timer to trigger initial EAPOL-Key 1st retry */
 | 
			
		||||
    trickle_t auth_trickle_timer;                          /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */
 | 
			
		||||
    trickle_params_t auth_trickle_params;                  /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */
 | 
			
		||||
    sec_prot_gtk_keys_t gtks;                              /**< GTKs */
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +103,7 @@ typedef struct {
 | 
			
		|||
    sec_prot_keys_nw_info_t sec_keys_nw_info;              /**< Security keys network information */
 | 
			
		||||
    timer_settings_t *timer_settings;                      /**< Timer settings */
 | 
			
		||||
    uint8_t nw_keys_used_cnt;                              /**< How many times bootstrap has been tried with current keys */
 | 
			
		||||
    uint8_t initial_key_retry_cnt;                         /**< initial EAPOL-Key retry counter */
 | 
			
		||||
    bool auth_trickle_running : 1;                         /**< Initial EAPOL-Key Trickle timer running */
 | 
			
		||||
    bool auth_requested : 1;                               /**< Authentication has been requested by the bootstrap */
 | 
			
		||||
    bool timer_running : 1;                                /**< Timer is running */
 | 
			
		||||
| 
						 | 
				
			
			@ -106,14 +112,34 @@ typedef struct {
 | 
			
		|||
    bool entry_address_active: 1;
 | 
			
		||||
} pae_supp_t;
 | 
			
		||||
 | 
			
		||||
// How many times sending of initial EAPOL-key is retried
 | 
			
		||||
#define INITIAL_KEY_RETRY_COUNT            2
 | 
			
		||||
 | 
			
		||||
#define TRICKLE_IMIN_180_SECS   180
 | 
			
		||||
// How many times sending of initial EAPOL-key is initiated on key update
 | 
			
		||||
#define KEY_UPDATE_RETRY_COUNT             3
 | 
			
		||||
#define LIFETIME_MISMATCH_RETRY_COUNT      1   /* No retries */
 | 
			
		||||
 | 
			
		||||
// How long the wait is before the first initial EAPOL-key retry
 | 
			
		||||
#define DEFAULT_INITIAL_KEY_RETRY_TIMER    120
 | 
			
		||||
#define NONE_INITIAL_KEY_RETRY_TIMER       0
 | 
			
		||||
 | 
			
		||||
// Default trickle values for sending of initial EAPOL-key
 | 
			
		||||
#define DEFAULT_TRICKLE_IMIN_SECS          360   /* 6 to 12 minutes */
 | 
			
		||||
#define DEFAULT_TRICKLE_IMAX_SECS          720
 | 
			
		||||
 | 
			
		||||
// Very slow network values for sending of initial EAPOL-key
 | 
			
		||||
#define VERY_SLOW_NW_TRICKLE_IMIN_SECS     600   /* 10 to 60 minutes */
 | 
			
		||||
#define VERY_SLOW_NW_TRICKLE_IMAX_SECS     3600
 | 
			
		||||
 | 
			
		||||
// Trickle timer on how long to wait response after last retry before failing authentication
 | 
			
		||||
#define LAST_INTERVAL_TRICKLE_IMIN_SECS    240   /* 4 minutes */
 | 
			
		||||
#define LAST_INTERVAL_TRICKLE_IMAX_SECS    240
 | 
			
		||||
 | 
			
		||||
static trickle_params_t initial_eapol_key_trickle_params = {
 | 
			
		||||
    .Imin = TRICKLE_IMIN_180_SECS,          /* 180 second; ticks are 1 second */
 | 
			
		||||
    .Imax = TRICKLE_IMIN_180_SECS << 1,     /* 360 second */
 | 
			
		||||
    .Imin = DEFAULT_TRICKLE_IMIN_SECS,    /* 360 second; ticks are 1 second */
 | 
			
		||||
    .Imax = DEFAULT_TRICKLE_IMAX_SECS,    /* 720 second */
 | 
			
		||||
    .k = 0,                               /* infinity - no consistency checking */
 | 
			
		||||
                                  .TimerExpirations = 3
 | 
			
		||||
    .TimerExpirations = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ws_pae_supp_free(pae_supp_t *pae_supp);
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +152,10 @@ static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp);
 | 
			
		|||
static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr);
 | 
			
		||||
static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data);
 | 
			
		||||
static void ws_pae_supp_tasklet_handler(arm_event_s *event);
 | 
			
		||||
static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp);
 | 
			
		||||
static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp);
 | 
			
		||||
static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations);
 | 
			
		||||
static bool ws_pae_supp_authentication_ongoing(pae_supp_t *pae_supp);
 | 
			
		||||
static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp);
 | 
			
		||||
static int8_t ws_pae_supp_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp);
 | 
			
		||||
static int8_t ws_pae_supp_timer_start(pae_supp_t *pae_supp);
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +168,7 @@ static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t
 | 
			
		|||
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp);
 | 
			
		||||
static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64);
 | 
			
		||||
static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
 | 
			
		||||
static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp);
 | 
			
		||||
 | 
			
		||||
static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
 | 
			
		||||
static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
 | 
			
		||||
| 
						 | 
				
			
			@ -156,6 +187,7 @@ static const char *KEYS_FILE = KEYS_FILE_NAME;
 | 
			
		|||
 | 
			
		||||
static int8_t tasklet_id = -1;
 | 
			
		||||
static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link);
 | 
			
		||||
static uint8_t timing_value = 0; // Timing value set based e.g. on network size
 | 
			
		||||
 | 
			
		||||
static void ws_pae_supp_address_set(pae_supp_t *pae_supp, kmp_addr_t *address)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -291,6 +323,23 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *gtkhash = pae_supp->gtk_hash_ptr_get(pae_supp->interface_ptr);
 | 
			
		||||
    if (!gtkhash) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check GTK hashes and initiate EAPOL procedure if mismatch is detected */
 | 
			
		||||
    gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash);
 | 
			
		||||
    if (mismatch != GTK_NO_MISMATCH) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tr_info("GTKs match to GTK hash");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
 | 
			
		||||
{
 | 
			
		||||
    pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -307,30 +356,21 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt
 | 
			
		|||
                trace_array(>khash[16], 8),
 | 
			
		||||
                trace_array(>khash[24], 8));
 | 
			
		||||
 | 
			
		||||
        // Mismatch, initiate EAPOL
 | 
			
		||||
        if (!pae_supp->auth_trickle_running) {
 | 
			
		||||
            uint8_t timer_expirations = 3;
 | 
			
		||||
        /* Mismatch, initiate EAPOL (if authentication not already ongoing or if not on
 | 
			
		||||
           wait time for the authenticator to answer) */
 | 
			
		||||
        if (!pae_supp->auth_trickle_running || pae_supp->initial_key_retry_cnt == 0) {
 | 
			
		||||
            uint8_t timer_expirations = KEY_UPDATE_RETRY_COUNT;
 | 
			
		||||
            // For GTK lifetime mismatch send only once
 | 
			
		||||
            if (mismatch == GTK_LIFETIME_MISMATCH) {
 | 
			
		||||
                timer_expirations = 1;
 | 
			
		||||
                timer_expirations = LIFETIME_MISMATCH_RETRY_COUNT;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin;
 | 
			
		||||
            pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax;
 | 
			
		||||
            pae_supp->auth_trickle_params.k = 0;
 | 
			
		||||
            pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
 | 
			
		||||
 | 
			
		||||
            // Starts trickle
 | 
			
		||||
            trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
 | 
			
		||||
            pae_supp->auth_trickle_running = true;
 | 
			
		||||
            // Start trickle timer
 | 
			
		||||
            ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, timer_expirations);
 | 
			
		||||
 | 
			
		||||
            // Starts supplicant timer
 | 
			
		||||
            ws_pae_supp_timer_start(pae_supp);
 | 
			
		||||
 | 
			
		||||
            tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->timer_settings->gtk_request_imin, pae_supp->timer_settings->gtk_request_imax, pae_supp->timer_settings->gtk_max_mismatch, pae_supp->auth_trickle_timer.t);
 | 
			
		||||
        } else {
 | 
			
		||||
            // If trickle is already running, set inconsistent heard to speed up the trickle
 | 
			
		||||
            trickle_inconsistent_heard(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -565,7 +605,7 @@ static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_i
 | 
			
		|||
    sec_keys_nw_info->updated = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set)
 | 
			
		||||
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get)
 | 
			
		||||
{
 | 
			
		||||
    pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
 | 
			
		||||
    if (!pae_supp) {
 | 
			
		||||
| 
						 | 
				
			
			@ -575,6 +615,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
 | 
			
		|||
    pae_supp->auth_completed = completed;
 | 
			
		||||
    pae_supp->nw_key_insert = nw_key_insert;
 | 
			
		||||
    pae_supp->nw_key_index_set = nw_key_index_set;
 | 
			
		||||
    pae_supp->gtk_hash_ptr_get = gtk_hash_ptr_get;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings)
 | 
			
		||||
| 
						 | 
				
			
			@ -596,9 +637,12 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
 | 
			
		|||
    pae_supp->auth_completed = NULL;
 | 
			
		||||
    pae_supp->nw_key_insert = NULL;
 | 
			
		||||
    pae_supp->nw_key_index_set = NULL;
 | 
			
		||||
    pae_supp->gtk_hash_ptr_get = NULL;
 | 
			
		||||
    pae_supp->initial_key_timer = 0;
 | 
			
		||||
    pae_supp->initial_key_retry_timer = 0;
 | 
			
		||||
    pae_supp->nw_keys_used_cnt = 0;
 | 
			
		||||
    pae_supp->timer_settings = timer_settings;
 | 
			
		||||
    pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT;
 | 
			
		||||
    pae_supp->auth_trickle_running = false;
 | 
			
		||||
    pae_supp->auth_requested = false;
 | 
			
		||||
    pae_supp->timer_running = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -702,6 +746,7 @@ int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr)
 | 
			
		|||
 | 
			
		||||
int8_t ws_pae_supp_timing_adjust(uint8_t timing)
 | 
			
		||||
{
 | 
			
		||||
    timing_value = timing;
 | 
			
		||||
    supp_fwh_sec_prot_timing_adjust(timing);
 | 
			
		||||
    supp_eap_sec_prot_timing_adjust(timing);
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -801,7 +846,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks)
 | 
			
		|||
        bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout);
 | 
			
		||||
 | 
			
		||||
        // Checks whether timer needs to be active
 | 
			
		||||
        if (!pae_supp->initial_key_timer && !pae_supp->auth_trickle_running && !running) {
 | 
			
		||||
        if (!ws_pae_supp_authentication_ongoing(pae_supp) && !running) {
 | 
			
		||||
            tr_debug("PAE idle");
 | 
			
		||||
            // If not already completed, restart bootstrap
 | 
			
		||||
            ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
 | 
			
		||||
| 
						 | 
				
			
			@ -811,22 +856,71 @@ void ws_pae_supp_fast_timer(uint16_t ticks)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ws_pae_supp_authentication_ongoing(pae_supp_t *pae_supp)
 | 
			
		||||
{
 | 
			
		||||
    /* When either bootstrap initial authentication or re-authentication is ongoing */
 | 
			
		||||
    if (pae_supp->initial_key_timer || pae_supp->auth_trickle_running ||
 | 
			
		||||
            ws_pae_lib_supp_timer_is_running(&pae_supp->entry)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ws_pae_supp_slow_timer(uint16_t seconds)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) {
 | 
			
		||||
 | 
			
		||||
        // Checks whether initial EAPOL-Key message needs to be re-send or new GTK request to be sent
 | 
			
		||||
        if (pae_supp->auth_trickle_running) {
 | 
			
		||||
            if (pae_supp->initial_key_retry_timer > 0) {
 | 
			
		||||
                if (pae_supp->initial_key_retry_timer > seconds) {
 | 
			
		||||
                    pae_supp->initial_key_retry_timer -= seconds;
 | 
			
		||||
                } else {
 | 
			
		||||
                    pae_supp->initial_key_retry_timer = 0;
 | 
			
		||||
                    tr_info("initial key retry timer expired");
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // Checks if trickle timer expires
 | 
			
		||||
                if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) {
 | 
			
		||||
                    if (pae_supp->initial_key_retry_cnt > 0) {
 | 
			
		||||
                        if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
 | 
			
		||||
                            tr_info("EAPOL-Key send failed");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            // Maximum number of trickle expires, authentication fails
 | 
			
		||||
 | 
			
		||||
                    /* Wait time for the authenticator to answer the last re-transmit expires;
 | 
			
		||||
                       fails authentication */
 | 
			
		||||
                    if (pae_supp->initial_key_retry_cnt == 0) {
 | 
			
		||||
                        bool retry = false;
 | 
			
		||||
                        // If making key update and GTKs do not match to GTK hash
 | 
			
		||||
                        if (!pae_supp->auth_requested && ws_pae_supp_gtk_hash_mismatch_check(pae_supp) < 0) {
 | 
			
		||||
                            tr_info("GTKs do not match to GTK hash");
 | 
			
		||||
                            retry = true;
 | 
			
		||||
                        }
 | 
			
		||||
                        ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
 | 
			
		||||
                        if (retry) {
 | 
			
		||||
                            // Start trickle timer to try re-authentication
 | 
			
		||||
                            ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, KEY_UPDATE_RETRY_COUNT);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (pae_supp->initial_key_retry_cnt > 0) {
 | 
			
		||||
                            pae_supp->initial_key_retry_cnt--;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (pae_supp->initial_key_retry_cnt == 0) {
 | 
			
		||||
                            // Starts wait time for the authenticator to answer
 | 
			
		||||
                            tr_info("Initial EAPOL-Key wait for last re-transmit answer");
 | 
			
		||||
                            ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Sanity check, should be running until authentication failure
 | 
			
		||||
                if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) {
 | 
			
		||||
                    ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Decrements GTK lifetimes
 | 
			
		||||
        for (uint8_t i = 0; i < GTK_NUM; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -846,14 +940,74 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
 | 
			
		|||
                if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
 | 
			
		||||
                    tr_info("EAPOL-Key send failed");
 | 
			
		||||
                }
 | 
			
		||||
                // Start trickle timer
 | 
			
		||||
                ws_pae_supp_initial_trickle_timer_start(pae_supp);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
                // Starts trickle
 | 
			
		||||
static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp)
 | 
			
		||||
{
 | 
			
		||||
    pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
 | 
			
		||||
 | 
			
		||||
    // Very fast, medium and slow network
 | 
			
		||||
    if (timing_value < 25) {
 | 
			
		||||
        /* Starts trickle for initial EAPOL-key. Sequence has fixed delay of 2 minutes,
 | 
			
		||||
         * one re-transmit interval, last re-transmit interval transmit time and a wait time
 | 
			
		||||
         * for the authenticator to answer the last re-transmit.
 | 
			
		||||
         *
 | 
			
		||||
         * Interval I [6,12] minutes. Sequence:
 | 
			
		||||
         *
 | 
			
		||||
         * fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes
 | 
			
		||||
         *
 | 
			
		||||
         * There are two retries. Minimum time that sequence takes before authentication failure
 | 
			
		||||
         * is 16 minutes and maximum is 30 minutes.
 | 
			
		||||
         */
 | 
			
		||||
        pae_supp->initial_key_retry_timer = DEFAULT_INITIAL_KEY_RETRY_TIMER; // 2 minutes
 | 
			
		||||
    } else {
 | 
			
		||||
        /* Extremely slow network
 | 
			
		||||
         *
 | 
			
		||||
         * Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence:
 | 
			
		||||
         * I + last I transmit time t + wait for answer [2,4] minutes
 | 
			
		||||
         * There are two retries. Minimum time that sequence takes before authentication failure
 | 
			
		||||
         * is 22 minutes and maximum is 124 minutes.
 | 
			
		||||
         */
 | 
			
		||||
        pae_supp->auth_trickle_params.Imin = VERY_SLOW_NW_TRICKLE_IMIN_SECS;
 | 
			
		||||
        pae_supp->auth_trickle_params.Imax = VERY_SLOW_NW_TRICKLE_IMAX_SECS;
 | 
			
		||||
        pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds
 | 
			
		||||
    }
 | 
			
		||||
    trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
 | 
			
		||||
    tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
 | 
			
		||||
    pae_supp->auth_trickle_running = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp)
 | 
			
		||||
{
 | 
			
		||||
    // Starts trickle last to wait response after last retry before failing authentication
 | 
			
		||||
    pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
 | 
			
		||||
    pae_supp->auth_trickle_params.Imin = LAST_INTERVAL_TRICKLE_IMIN_SECS;
 | 
			
		||||
    pae_supp->auth_trickle_params.Imax = LAST_INTERVAL_TRICKLE_IMAX_SECS;
 | 
			
		||||
    pae_supp->auth_trickle_params.TimerExpirations = 1;
 | 
			
		||||
    // Set I to [iMin,iMax] (4 to 4 minutes) -> t is [I/2 - I] (2 minutes to 4 minutes)
 | 
			
		||||
    trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
 | 
			
		||||
    tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations)
 | 
			
		||||
{
 | 
			
		||||
    // Starts trickle for the key update
 | 
			
		||||
    pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin;
 | 
			
		||||
    pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax;
 | 
			
		||||
    pae_supp->auth_trickle_params.k = 0;
 | 
			
		||||
    pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
 | 
			
		||||
 | 
			
		||||
    trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
 | 
			
		||||
    tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
 | 
			
		||||
    pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds
 | 
			
		||||
    pae_supp->auth_trickle_running = true;
 | 
			
		||||
    pae_supp->initial_key_retry_cnt = timer_expirations;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp)
 | 
			
		||||
| 
						 | 
				
			
			@ -947,7 +1101,7 @@ static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *int
 | 
			
		|||
        const uint8_t *parent_ll_addr = rpl_control_preferred_parent_addr(instance, false);
 | 
			
		||||
        if (parent_ll_addr) {
 | 
			
		||||
            memcpy(eui_64, &parent_ll_addr[8], 8);
 | 
			
		||||
            eui_64[0] |= 0x02;
 | 
			
		||||
            eui_64[0] ^= 0x02;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1014,14 +1168,13 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_
 | 
			
		|||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!pae_supp->entry_address_active) {
 | 
			
		||||
    // If target address is not set or authentication is not ongoing
 | 
			
		||||
    if (!pae_supp->entry_address_active || !ws_pae_supp_authentication_ongoing(pae_supp)) {
 | 
			
		||||
        tr_info("Incoming KMP rejected, auth not ongoing, type: %i ", type);
 | 
			
		||||
        // Does no longer wait for authentication, ignores message
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // No longer runs trickle timer for re-sending initial EAPOL-key
 | 
			
		||||
    pae_supp->auth_trickle_running = false;
 | 
			
		||||
 | 
			
		||||
    // Updates parent address
 | 
			
		||||
    kmp_address_copy(&pae_supp->entry.addr, addr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1040,6 +1193,9 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_
 | 
			
		|||
    // Create new instance
 | 
			
		||||
    kmp = ws_pae_supp_kmp_create_and_start(service, type, pae_supp);
 | 
			
		||||
 | 
			
		||||
    // Adds ticks to wait for authenticator to continue timer
 | 
			
		||||
    ws_pae_lib_supp_timer_ticks_add(&pae_supp->entry, START_AUTHENTICATION_TICKS);
 | 
			
		||||
 | 
			
		||||
    // For EAP-TLS create also TLS in addition to EAP-TLS
 | 
			
		||||
    if (type == IEEE_802_1X_MKA) {
 | 
			
		||||
        if (ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, TLS_PROT) != NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,6 +1268,15 @@ static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ
 | 
			
		|||
    (void) addr;
 | 
			
		||||
    (void) type;
 | 
			
		||||
 | 
			
		||||
    kmp_service_t *service = kmp_api_service_get(kmp);
 | 
			
		||||
    pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service);
 | 
			
		||||
    if (!pae_supp) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Incoming KMP protocol has started, no longer runs trickle timer for re-sending EAPOL-key message
 | 
			
		||||
    pae_supp->auth_trickle_running = false;
 | 
			
		||||
 | 
			
		||||
    // For now, accept every KMP-CREATE.indication
 | 
			
		||||
    kmp_api_create_response(kmp, KMP_RESULT_OK);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1148,7 +1313,6 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
 | 
			
		|||
        tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8));
 | 
			
		||||
        ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -236,6 +236,16 @@ typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interfa
 | 
			
		|||
 */
 | 
			
		||||
typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ws_pae_supp_gtk_hash_ptr_get get pointer to GTK hash storage callback
 | 
			
		||||
 *
 | 
			
		||||
 * \param interface_ptr interface
 | 
			
		||||
 *
 | 
			
		||||
 * \return pointer to GTK has storage or NULL
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ws_pae_supp_cb_register register PEA supplicant callbacks
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -245,7 +255,7 @@ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interf
 | 
			
		|||
 * \param nw_key_index_set network send key index callback
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set);
 | 
			
		||||
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get);
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -356,7 +356,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_aro_failure(cur_interface, src_addr, true);
 | 
			
		||||
        ws_common_aro_failure(cur_interface, src_addr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1389,7 +1389,7 @@ static void icmpv6_aro_cb(buffer_t *buf, uint8_t status)
 | 
			
		|||
    }
 | 
			
		||||
    rpl_control_address_register_done(buf->interface, ll_address, status);
 | 
			
		||||
    if (status != SOCKET_TX_DONE) {
 | 
			
		||||
        ws_common_aro_failure(buf->interface, ll_address, false);
 | 
			
		||||
        ws_common_aro_failure(buf->interface, ll_address);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1697,7 +1697,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
 | 
			
		|||
        memcpy(ptr, aro->eui64, 8);
 | 
			
		||||
        ptr += 8;
 | 
			
		||||
    }
 | 
			
		||||
    if (ws_info(cur) && aro && aro->status != ARO_SUCCESS) {
 | 
			
		||||
    if (ws_info(cur) && aro && (aro->status != ARO_SUCCESS && aro->status != ARO_TOPOLOGICALLY_INCORRECT)) {
 | 
			
		||||
        /*If Aro failed we will kill the neigbour after we have succeeded in sending message*/
 | 
			
		||||
        if (!ws_common_negative_aro_mark(cur, aro->eui64)) {
 | 
			
		||||
            tr_debug("Neighbour removed for negative response send");
 | 
			
		||||
| 
						 | 
				
			
			@ -1713,7 +1713,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
 | 
			
		|||
    buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP);
 | 
			
		||||
    buf->interface = cur;
 | 
			
		||||
 | 
			
		||||
    tr_debug("Build NA");
 | 
			
		||||
    tr_info("Build NA");
 | 
			
		||||
 | 
			
		||||
    return (buf);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,6 +117,7 @@ typedef enum slaac_src {
 | 
			
		|||
#define ARO_SUCCESS     0
 | 
			
		||||
#define ARO_DUPLICATE   1
 | 
			
		||||
#define ARO_FULL        2
 | 
			
		||||
#define ARO_TOPOLOGICALLY_INCORRECT 8
 | 
			
		||||
 | 
			
		||||
extern void icmpv6_init(void);
 | 
			
		||||
extern struct buffer *icmpv6_down(struct buffer *buf);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -325,6 +325,9 @@ void icmpv6_stop_router_advertisements(protocol_interface_info_entry_t *cur, con
 | 
			
		|||
 */
 | 
			
		||||
static void icmpv6_send_ra(protocol_interface_info_entry_t *cur, const uint8_t *dest, const uint8_t *abro)
 | 
			
		||||
{
 | 
			
		||||
#ifndef HAVE_RPL
 | 
			
		||||
    (void) abro;
 | 
			
		||||
#endif
 | 
			
		||||
    if (cur->nwk_id == IF_6LoWPAN) {
 | 
			
		||||
        nd_ra_build_by_abro(abro, dest, cur);
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -773,6 +773,9 @@ drop:
 | 
			
		|||
static buffer_t *ipv6_handle_options(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint8_t nh, uint16_t payload_length, uint16_t *hdrlen_out, const sockaddr_t *ll_src, bool pre_fragment)
 | 
			
		||||
{
 | 
			
		||||
    (void) nh;
 | 
			
		||||
#ifndef HAVE_RPL
 | 
			
		||||
    (void) ll_src;
 | 
			
		||||
#endif
 | 
			
		||||
    if (payload_length < 2) {
 | 
			
		||||
        return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -853,6 +856,9 @@ len_err:
 | 
			
		|||
 | 
			
		||||
static buffer_t *ipv6_handle_routing_header(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint16_t payload_length, uint16_t *hdrlen_out, bool *forward_out, bool pre_fragment)
 | 
			
		||||
{
 | 
			
		||||
#ifndef HAVE_RPL
 | 
			
		||||
    (void) forward_out;
 | 
			
		||||
#endif
 | 
			
		||||
    if (buf->options.ll_security_bypass_rx) {
 | 
			
		||||
        tr_warn("Routing header: Security check fail");
 | 
			
		||||
        protocol_stats_update(STATS_IP_RX_DROP, 1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,8 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#include "nsconfig.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include "ns_types.h"
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
#include "Core/include/ns_address_internal.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +31,13 @@
 | 
			
		|||
 | 
			
		||||
#define TRACE_GROUP "buff"
 | 
			
		||||
 | 
			
		||||
// Get module working also on 16-bit platform
 | 
			
		||||
#if INT_MAX < 0xFFFF
 | 
			
		||||
#define BUFFER_MAX_SIZE ((size_t)INT_MAX)
 | 
			
		||||
#else
 | 
			
		||||
#define BUFFER_MAX_SIZE ((size_t)0xFFFF)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
volatile unsigned int buffer_count = 0;
 | 
			
		||||
 | 
			
		||||
uint8_t *(buffer_corrupt_check)(buffer_t *buf)
 | 
			
		||||
| 
						 | 
				
			
			@ -38,15 +46,12 @@ uint8_t *(buffer_corrupt_check)(buffer_t *buf)
 | 
			
		|||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (buf->buf_ptr > buf->buf_end) {
 | 
			
		||||
        tr_error("Buffer pointer end not set");
 | 
			
		||||
    } else if (buffer_data_length(buf) < 0) {
 | 
			
		||||
        tr_error("Buffer length overflow");
 | 
			
		||||
        while (1);
 | 
			
		||||
    } else if (buf->buf_end > buf->size || buf->buf_ptr > buf->size) {
 | 
			
		||||
        tr_error("buffer pointer overridden");
 | 
			
		||||
    if (buf->buf_ptr > buf->buf_end || buf->buf_end > buf->size) {
 | 
			
		||||
        tr_error("Invalid buffer, size=%"PRIu16", buf_ptr=%"PRIu16", buf_end=%"PRIu16"", buf->size, buf->buf_ptr, buf->buf_end);
 | 
			
		||||
        tr_error("Data: %s", tr_array(buffer_data_pointer(buf), 56));
 | 
			
		||||
        while (1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return buffer_data_pointer(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -71,8 +76,8 @@ buffer_t *buffer_get_minimal(uint16_t size)
 | 
			
		|||
 */
 | 
			
		||||
buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspace)
 | 
			
		||||
{
 | 
			
		||||
    buffer_t *buf;
 | 
			
		||||
    uint16_t total_size;
 | 
			
		||||
    buffer_t *buf = NULL;
 | 
			
		||||
    uint32_t total_size;
 | 
			
		||||
 | 
			
		||||
    total_size = headroom + size;
 | 
			
		||||
    if (total_size < minspace) {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,10 +88,12 @@ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspac
 | 
			
		|||
     * anyway be this much aligned. */
 | 
			
		||||
    total_size = (total_size + 3) & ~ 3;
 | 
			
		||||
 | 
			
		||||
    if (total_size <= BUFFER_MAX_SIZE) {
 | 
			
		||||
        // Note - as well as this alloc+init, buffers can also be "realloced"
 | 
			
		||||
        // in buffer_headroom()
 | 
			
		||||
 | 
			
		||||
        buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + total_size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (buf) {
 | 
			
		||||
        platform_enter_critical();
 | 
			
		||||
        buffer_count++;
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +117,7 @@ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspac
 | 
			
		|||
#endif
 | 
			
		||||
        buf->size = total_size;
 | 
			
		||||
    } else {
 | 
			
		||||
        tr_error("buffer_get failed: alloc(%d)", (int) sizeof(buffer_t) + total_size);
 | 
			
		||||
        tr_error("buffer_get failed: alloc(%"PRIu32")", (uint32_t)(sizeof(buffer_t) + total_size));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protocol_stats_update(STATS_BUFFER_ALLOC, 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -130,10 +137,14 @@ buffer_t *buffer_headroom(buffer_t *buf, uint16_t size)
 | 
			
		|||
    uint16_t curr_len = buffer_data_length(buf);
 | 
			
		||||
 | 
			
		||||
    if (buf->size < (curr_len + size)) {
 | 
			
		||||
        buffer_t *restrict new_buf = NULL;
 | 
			
		||||
        /* This buffer isn't big enough at all - allocate a new block */
 | 
			
		||||
        // TODO - should we be giving them extra? probably
 | 
			
		||||
        uint16_t new_total = (curr_len + size + 3) & ~ 3;
 | 
			
		||||
        buffer_t *restrict new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total);
 | 
			
		||||
        uint32_t new_total = (curr_len + size + 3) & ~ 3;
 | 
			
		||||
        if (new_total <= BUFFER_MAX_SIZE) {
 | 
			
		||||
            new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (new_buf) {
 | 
			
		||||
            // Copy the buffer_t header
 | 
			
		||||
            *new_buf = *buf;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -322,7 +322,7 @@ struct socket *buffer_socket_set(buffer_t *buf, struct socket *socket);
 | 
			
		|||
        } while(0)
 | 
			
		||||
 | 
			
		||||
/** get data length*/
 | 
			
		||||
#define buffer_data_length(x)  (int16_t)(x->buf_end - x->buf_ptr)
 | 
			
		||||
#define buffer_data_length(x)  (int)(x->buf_end - x->buf_ptr)
 | 
			
		||||
 | 
			
		||||
/** get data length Set*/
 | 
			
		||||
#define buffer_data_length_set(x,z)  ((x)->buf_end = (x)->buf_ptr + (z))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -287,14 +287,16 @@ void socket_release(socket_t *socket)
 | 
			
		|||
        if (tcp_info(socket->inet_pcb)) {
 | 
			
		||||
            /* This may trigger a reset if pending data. Do it first so you
 | 
			
		||||
             * get just the reset, rather than a FIN. */
 | 
			
		||||
            tcp_session_shutdown_read(tcp_info(socket->inet_pcb));
 | 
			
		||||
            tcp_error sock_status = tcp_session_shutdown_read(tcp_info(socket->inet_pcb));
 | 
			
		||||
            /* This can also cause TCP deletion */
 | 
			
		||||
            if (tcp_info(socket->inet_pcb)) {
 | 
			
		||||
                tcp_session_close(tcp_info(socket->inet_pcb));
 | 
			
		||||
                sock_status = tcp_session_close(tcp_info(socket->inet_pcb));
 | 
			
		||||
            }
 | 
			
		||||
            if (tcp_info(socket->inet_pcb)) {
 | 
			
		||||
                tcp_socket_released(tcp_info(socket->inet_pcb));
 | 
			
		||||
            }
 | 
			
		||||
            // prevent warning "statement with no effect" when TCP is disabled
 | 
			
		||||
            (void) sock_status;
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Unbind the internet control block - ensures users are not prevented
 | 
			
		||||
             * from binding a new socket to the same port if the socket lingers
 | 
			
		||||
| 
						 | 
				
			
			@ -1362,8 +1364,10 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr
 | 
			
		|||
 | 
			
		||||
    protocol_push(buf);
 | 
			
		||||
 | 
			
		||||
#ifndef NO_TCP
 | 
			
		||||
    /* TCP jumps back to here */
 | 
			
		||||
success:
 | 
			
		||||
#endif
 | 
			
		||||
    if (flags & NS_MSG_LEGACY0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,7 +87,7 @@ static void DHCP_server_service_timer_stop(void)
 | 
			
		|||
 | 
			
		||||
int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_reply_packet_s *replyPacket, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, dhcpv6_gua_response_t *response, bool allocateNew)
 | 
			
		||||
{
 | 
			
		||||
    dhcpv6_alloacted_address_entry_t *dhcp_allocated_address = NULL;
 | 
			
		||||
    dhcpv6_allocated_address_t *dhcp_allocated_address = NULL;
 | 
			
		||||
    dhcpv6_ia_non_temporal_address_s nonTemporalAddress;
 | 
			
		||||
    bool address_allocated = false;
 | 
			
		||||
    //Validate Client DUID
 | 
			
		||||
| 
						 | 
				
			
			@ -279,12 +279,15 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8],
 | 
			
		|||
{
 | 
			
		||||
    dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
 | 
			
		||||
    if (serverInfo) {
 | 
			
		||||
        ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
        ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
            //Delete Server data base
 | 
			
		||||
            if (serverInfo->removeCb) {
 | 
			
		||||
                serverInfo->removeCb(interface, cur->nonTemporalAddress, NULL);
 | 
			
		||||
                uint8_t allocated_address[16];
 | 
			
		||||
                libdhcpv6_allocated_address_write(allocated_address, cur, serverInfo);
 | 
			
		||||
                serverInfo->removeCb(interface, allocated_address, NULL);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (serverInfo->removeCb) {
 | 
			
		||||
            // Clean all /128 'Thread Proxy' routes to self and others added when acting as a DHCP server
 | 
			
		||||
            serverInfo->removeCb(interface, NULL, serverInfo->guaPrefix);
 | 
			
		||||
| 
						 | 
				
			
			@ -312,18 +315,22 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8],
 | 
			
		|||
 *  /param guaPrefix Prefix which will be removed
 | 
			
		||||
 *  /param mode true trig autonous mode, false define address by default suffics + client id
 | 
			
		||||
 */
 | 
			
		||||
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode)
 | 
			
		||||
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list)
 | 
			
		||||
{
 | 
			
		||||
    int retVal = -1;
 | 
			
		||||
    dhcpv6_gua_server_entry_s *serverInfo;
 | 
			
		||||
    dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
 | 
			
		||||
    if (!serverInfo) {
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
 | 
			
		||||
    if (serverInfo) {
 | 
			
		||||
        serverInfo->enableAddressAutonous = mode;
 | 
			
		||||
        retVal = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return retVal;
 | 
			
		||||
    serverInfo->enableAddressAutonous = mode;
 | 
			
		||||
    if (mode) {
 | 
			
		||||
        serverInfo->disableAddressListAllocation = autonomous_skip_list;
 | 
			
		||||
    } else {
 | 
			
		||||
        serverInfo->disableAddressListAllocation = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[static 16], dhcp_address_prefer_remove_cb *remove_cb, dhcp_address_add_notify_cb *add_cb)
 | 
			
		||||
| 
						 | 
				
			
			@ -365,18 +372,18 @@ int DHCPv6_server_service_duid_update(int8_t interface, uint8_t guaPrefix[static
 | 
			
		|||
 */
 | 
			
		||||
int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_t guaPrefix[static 16], uint32_t maxClientCount)
 | 
			
		||||
{
 | 
			
		||||
    int retVal = -1;
 | 
			
		||||
    dhcpv6_gua_server_entry_s *serverInfo;
 | 
			
		||||
    if (maxClientCount == 0) {
 | 
			
		||||
    if (maxClientCount == 0 || maxClientCount > MAX_SUPPORTED_ADDRESS_LIST_SIZE) {
 | 
			
		||||
        return -2;
 | 
			
		||||
    } else {
 | 
			
		||||
    }
 | 
			
		||||
    serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
 | 
			
		||||
        if (serverInfo) {
 | 
			
		||||
            serverInfo->maxSuppertedClients = maxClientCount;
 | 
			
		||||
            retVal = 0;
 | 
			
		||||
    if (!serverInfo) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
    return retVal;
 | 
			
		||||
 | 
			
		||||
    serverInfo->maxSupportedClients = maxClientCount;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** SET Address Valid Lifetime parameter for allocated address, Default is 7200 seconds
 | 
			
		||||
| 
						 | 
				
			
			@ -388,18 +395,17 @@ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_
 | 
			
		|||
 */
 | 
			
		||||
int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t guaPrefix[static 16], uint32_t validLifeTimne)
 | 
			
		||||
{
 | 
			
		||||
    int retVal = -1;
 | 
			
		||||
    dhcpv6_gua_server_entry_s *serverInfo;
 | 
			
		||||
    if (validLifeTimne < 120) {
 | 
			
		||||
        retVal = -2;
 | 
			
		||||
    } else {
 | 
			
		||||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
    serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
 | 
			
		||||
        if (serverInfo) {
 | 
			
		||||
    if (!serverInfo) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    serverInfo->validLifetime = validLifeTimne;
 | 
			
		||||
            retVal = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return retVal;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -422,11 +428,12 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds)
 | 
			
		|||
{
 | 
			
		||||
    (void) timeUpdateInSeconds;
 | 
			
		||||
}
 | 
			
		||||
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode)
 | 
			
		||||
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list)
 | 
			
		||||
{
 | 
			
		||||
    (void) interface;
 | 
			
		||||
    (void) guaPrefix;
 | 
			
		||||
    (void) mode;
 | 
			
		||||
    (void) autonomous_skip_list;
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,8 +66,9 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds);
 | 
			
		|||
 *  /param interface interface id of this thread instance.
 | 
			
		||||
 *  /param guaPrefix Prefix which will be removed
 | 
			
		||||
 *  /param mode true trig autonous mode, false define address by default suffics + client id
 | 
			
		||||
 *  /param autonomous_skip_list true skip address list allocation when autonous mode is selected
 | 
			
		||||
 */
 | 
			
		||||
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode);
 | 
			
		||||
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* SET max accepted clients to server, Default is 200
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -202,6 +202,7 @@ typedef struct protocol_interface_rf_mac_setup {
 | 
			
		|||
    mac_scan_type_t scan_type;
 | 
			
		||||
 | 
			
		||||
    uint8_t mac_channel;
 | 
			
		||||
    uint8_t mac_tx_start_channel;
 | 
			
		||||
    //uint8_t cca_failure;
 | 
			
		||||
 | 
			
		||||
    /* MAC TX Queue */
 | 
			
		||||
| 
						 | 
				
			
			@ -244,6 +245,7 @@ typedef struct protocol_interface_rf_mac_setup {
 | 
			
		|||
    uint32_t mlme_tick_count;
 | 
			
		||||
    uint32_t symbol_rate;
 | 
			
		||||
    uint32_t symbol_time_us;
 | 
			
		||||
    uint32_t datarate;
 | 
			
		||||
    uint8_t max_ED;
 | 
			
		||||
    uint16_t mlme_ED_counter;
 | 
			
		||||
    mac_tx_status_t mac_tx_status;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,8 +57,13 @@ uint32_t mac_read_phy_datarate(const fhss_api_t *fhss_api)
 | 
			
		|||
    if (!mac_setup) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t datarate = dev_get_phy_datarate(mac_setup->dev_driver->phy_driver, mac_setup->mac_channel_list.channel_page);
 | 
			
		||||
    // If datarate is not set, use default 250kbit/s.
 | 
			
		||||
    uint32_t datarate = 0;
 | 
			
		||||
    // When channel page is set, ask data rate directly from PHY driver, otherwise use data rate configured to MAC. Ultimately, use default value instead 0.
 | 
			
		||||
    if (mac_setup->mac_channel_list.channel_page != CHANNEL_PAGE_UNDEFINED) {
 | 
			
		||||
        datarate = dev_get_phy_datarate(mac_setup->dev_driver->phy_driver, mac_setup->mac_channel_list.channel_page);
 | 
			
		||||
    } else if (mac_setup->datarate) {
 | 
			
		||||
        datarate = mac_setup->datarate;
 | 
			
		||||
    }
 | 
			
		||||
    if (!datarate) {
 | 
			
		||||
        datarate = 250000;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1321,7 +1321,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_
 | 
			
		|||
    timer_mac_stop(rf_mac_setup);
 | 
			
		||||
    if (m_event == MAC_CCA_FAIL) {
 | 
			
		||||
        sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_CCA_FAIL, 0);
 | 
			
		||||
        tr_debug("MAC CCA fail");
 | 
			
		||||
        tr_info("MAC CCA fail");
 | 
			
		||||
        /* CCA fail */
 | 
			
		||||
        //rf_mac_setup->cca_failure++;
 | 
			
		||||
        buf->status = MLME_BUSY_CHAN;
 | 
			
		||||
| 
						 | 
				
			
			@ -1329,7 +1329,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_
 | 
			
		|||
        sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_COUNT, buf->mac_payload_length);
 | 
			
		||||
        if (m_event == MAC_TX_FAIL) {
 | 
			
		||||
            sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_FAIL, 0);
 | 
			
		||||
            tr_debug("MAC tx fail");
 | 
			
		||||
            tr_info("MAC tx fail");
 | 
			
		||||
            buf->status = MLME_TX_NO_ACK;
 | 
			
		||||
        } else if (m_event == MAC_TX_DONE) {
 | 
			
		||||
            if (mac_is_ack_request_set(buf) == false) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1430,7 +1430,7 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr,
 | 
			
		|||
    if (rf_ptr->fhss_api && !buffer->asynch_request) {
 | 
			
		||||
        // FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted
 | 
			
		||||
        if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) {
 | 
			
		||||
            if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype)) == true) {
 | 
			
		||||
            if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), rf_ptr->mac_tx_start_channel) == true) {
 | 
			
		||||
 | 
			
		||||
                if (rf_ptr->mac_tx_result == MAC_TX_FAIL) {
 | 
			
		||||
                    buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry;
 | 
			
		||||
| 
						 | 
				
			
			@ -1921,6 +1921,7 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma
 | 
			
		|||
    memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t));
 | 
			
		||||
    rf_ptr->mac_cca_retry = 0;
 | 
			
		||||
    rf_ptr->mac_tx_retry = 0;
 | 
			
		||||
    rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel;
 | 
			
		||||
    mac_csma_param_init(rf_ptr);
 | 
			
		||||
    if (mcps_generic_packet_build(rf_ptr, buffer) != 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -783,6 +783,7 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m
 | 
			
		|||
            rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_RF_CONFIGURATION, (uint8_t *) set_req->value_pointer);
 | 
			
		||||
            mac_mlme_set_symbol_rate(rf_mac_setup);
 | 
			
		||||
            phy_rf_channel_configuration_s *config_params = (phy_rf_channel_configuration_s *)set_req->value_pointer;
 | 
			
		||||
            rf_mac_setup->datarate = config_params->datarate;
 | 
			
		||||
            tr_info("RF config update:");
 | 
			
		||||
            tr_info("Frequency(ch0): %"PRIu32"Hz", config_params->channel_0_center_frequency);
 | 
			
		||||
            tr_info("Channel spacing: %"PRIu32"Hz", config_params->channel_spacing);
 | 
			
		||||
| 
						 | 
				
			
			@ -1090,6 +1091,7 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a
 | 
			
		|||
    entry->aUnitBackoffPeriod = 20; //This can be different in some Platform 20 comes from 12-symbol turnaround and 8 symbol CCA read
 | 
			
		||||
    entry->number_of_csma_ca_periods = MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS;
 | 
			
		||||
    entry->multi_cca_interval = MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL;
 | 
			
		||||
    entry->mac_channel_list.channel_page = CHANNEL_PAGE_UNDEFINED;
 | 
			
		||||
 | 
			
		||||
    if (mac_sec_mib_init(entry, storage_sizes) != 0) {
 | 
			
		||||
        mac_mlme_data_base_deallocate(entry);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -429,7 +429,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
 | 
			
		|||
 | 
			
		||||
        if (rf_ptr->mac_ack_tx_active) {
 | 
			
		||||
            //Accept direct non crypted acks and crypted only if neighbor is at list
 | 
			
		||||
            if (rf_ptr->ack_tx_possible || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
 | 
			
		||||
            if (rf_ptr->ack_tx_possible) {
 | 
			
		||||
                return PHY_TX_ALLOWED;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -481,10 +481,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
 | 
			
		|||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    bool waiting_ack = false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (rf_ptr->mac_ack_tx_active) {
 | 
			
		||||
        mac_data_ack_tx_finish(rf_ptr);
 | 
			
		||||
        return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -506,11 +502,40 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
 | 
			
		|||
        timer_mac_stop(rf_ptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rf_ptr->fhss_api && rf_ptr->active_pd_data_request->asynch_request == false) {
 | 
			
		||||
        /* waiting_ack == false allows FHSS to change back to RX channel after transmission
 | 
			
		||||
         * tx_completed == true allows FHSS to delete stored failure handles
 | 
			
		||||
         */
 | 
			
		||||
        bool waiting_ack = false, tx_completed = false;
 | 
			
		||||
        if (status == PHY_LINK_TX_SUCCESS && !rf_ptr->macTxRequestAck) {
 | 
			
		||||
            waiting_ack = false;
 | 
			
		||||
            tx_completed = true;
 | 
			
		||||
        } else if (status == PHY_LINK_TX_SUCCESS && rf_ptr->macTxRequestAck) {
 | 
			
		||||
            waiting_ack = true;
 | 
			
		||||
            tx_completed = false;
 | 
			
		||||
        } else if (status == PHY_LINK_CCA_FAIL) {
 | 
			
		||||
            waiting_ack = false;
 | 
			
		||||
            tx_completed = false;
 | 
			
		||||
        } else if (status == PHY_LINK_CCA_OK) {
 | 
			
		||||
            waiting_ack = false;
 | 
			
		||||
            tx_completed = false;
 | 
			
		||||
        } else if (status == PHY_LINK_TX_FAIL) {
 | 
			
		||||
            waiting_ack = false;
 | 
			
		||||
            tx_completed = false;
 | 
			
		||||
        } else if (status == PHY_LINK_TX_DONE) {
 | 
			
		||||
            waiting_ack = false;
 | 
			
		||||
            tx_completed = true;
 | 
			
		||||
        } else if (status == PHY_LINK_TX_DONE_PENDING) {
 | 
			
		||||
            waiting_ack = false;
 | 
			
		||||
            tx_completed = true;
 | 
			
		||||
        }
 | 
			
		||||
        rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_completed, rf_ptr->active_pd_data_request->msduHandle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (status) {
 | 
			
		||||
        case PHY_LINK_TX_SUCCESS:
 | 
			
		||||
            if (rf_ptr->macTxRequestAck) {
 | 
			
		||||
                timer_mac_start(rf_ptr, MAC_TIMER_ACK, rf_ptr->mac_ack_wait_duration); /*wait for ACK 1 ms*/
 | 
			
		||||
                waiting_ack = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                //TODO CHECK this is MAC_TX_ PERMIT OK
 | 
			
		||||
                mac_tx_done_state_set(rf_ptr, MAC_TX_DONE);
 | 
			
		||||
| 
						 | 
				
			
			@ -540,15 +565,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
 | 
			
		|||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    if (rf_ptr->fhss_api) {
 | 
			
		||||
        bool tx_is_done = false;
 | 
			
		||||
        if (rf_ptr->mac_tx_result == MAC_TX_DONE) {
 | 
			
		||||
            tx_is_done = true;
 | 
			
		||||
        }
 | 
			
		||||
        if (rf_ptr->active_pd_data_request->asynch_request == false) {
 | 
			
		||||
            rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_is_done, rf_ptr->active_pd_data_request->msduHandle);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -772,7 +788,7 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr,
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0 || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
 | 
			
		||||
    if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
 | 
			
		||||
        rf_ptr->ack_tx_possible = true;
 | 
			
		||||
    } else {
 | 
			
		||||
        rf_ptr->ack_tx_possible = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -874,6 +890,11 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
 | 
			
		|||
 | 
			
		||||
    if (message->id == MAC15_4_PD_SAP_DATA_IND) {
 | 
			
		||||
        arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind);
 | 
			
		||||
        mac_pre_parsed_frame_t *buffer = NULL;
 | 
			
		||||
        if (pd_data_ind->data_len == 0) {
 | 
			
		||||
            goto ERROR_HANDLER;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pd_data_ind->data_len < 3) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -881,7 +902,7 @@ 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);
 | 
			
		||||
 | 
			
		||||
        mac_pre_parsed_frame_t *buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
 | 
			
		||||
        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) {
 | 
			
		||||
            goto ERROR_HANDLER;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -919,7 +940,12 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
 | 
			
		|||
        }
 | 
			
		||||
ERROR_HANDLER:
 | 
			
		||||
        mcps_sap_pre_parsed_frame_buffer_free(buffer);
 | 
			
		||||
        if (pd_data_ind->data_len >= 3) {
 | 
			
		||||
            sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
 | 
			
		||||
        }
 | 
			
		||||
        if (rf_ptr->fhss_api) {
 | 
			
		||||
            rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0);
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    } else if (message->id == MAC15_4_PD_SAP_DATA_TX_CONFIRM) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -281,6 +281,7 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de
 | 
			
		|||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
    mlme_device_descriptor_t *device_ptr = rf_mac_setup->device_description_table + atribute_index;
 | 
			
		||||
 | 
			
		||||
    //Copy description
 | 
			
		||||
| 
						 | 
				
			
			@ -293,6 +294,24 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de
 | 
			
		|||
    //tr_debug("Set %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_descriptor->ShortAddress, trace_array(device_descriptor->ExtAddress, 8), device_descriptor->FrameCounter);
 | 
			
		||||
 | 
			
		||||
    *device_ptr = *device_descriptor;
 | 
			
		||||
 | 
			
		||||
    if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible &&
 | 
			
		||||
            device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) {
 | 
			
		||||
 | 
			
		||||
        //Compare address for pending neigbour add
 | 
			
		||||
        if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) {
 | 
			
		||||
            uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr);
 | 
			
		||||
            if (short_id == device_ptr->ShortAddress) {
 | 
			
		||||
                rf_mac_setup->ack_tx_possible = true;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) {
 | 
			
		||||
            if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) {
 | 
			
		||||
                rf_mac_setup->ack_tx_possible = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -197,6 +197,20 @@ int ns_sw_mac_fhss_register(mac_api_t *mac_api, fhss_api_t *fhss_api)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ns_sw_mac_fhss_unregister(mac_api_t *mac_api)
 | 
			
		||||
{
 | 
			
		||||
    if (!mac_api) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    // Get a pointer to MAC setup structure
 | 
			
		||||
    protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_mac_api(mac_api);
 | 
			
		||||
    if (!mac_setup) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    mac_setup->fhss_api = NULL;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct fhss_api *ns_sw_mac_get_fhss_api(struct mac_api_s *mac_api)
 | 
			
		||||
{
 | 
			
		||||
    if (!mac_api) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -603,6 +603,7 @@ static protocol_interface_info_entry_t *protocol_core_interface_6lowpan_entry_ge
 | 
			
		|||
    entry->mac_parameters->mac_prev_key_attribute_id = 0;
 | 
			
		||||
    entry->mac_parameters->mac_default_key_attribute_id = 1;
 | 
			
		||||
    entry->mac_parameters->mac_next_key_attribute_id = 2;
 | 
			
		||||
    entry->mac_parameters->mac_default_key_index = 0;
 | 
			
		||||
 | 
			
		||||
    entry->beacon_cb = beacon_received;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1116,10 +1117,10 @@ void nwk_bootsrap_state_update(arm_nwk_interface_status_type_e posted_event, pro
 | 
			
		|||
            default:
 | 
			
		||||
                mac_data_poll_protocol_poll_mode_disable(cur);
 | 
			
		||||
                if (!cur->rpl_domain) {
 | 
			
		||||
                    tr_debug("NON RPL Ready");
 | 
			
		||||
                    tr_info("NON RPL Ready");
 | 
			
		||||
                    //nwk_protocol_poll_mode_disable(cur->nwk_id, 0);
 | 
			
		||||
                } else {
 | 
			
		||||
                    tr_debug("RPL Ready");
 | 
			
		||||
                    tr_info("RPL Ready");
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,8 +60,8 @@
 | 
			
		|||
const uint8_t ADDR_LINK_LOCAL_ALL_RPL_NODES[16] = { 0xff, 0x02, [15] = 0x1a };
 | 
			
		||||
 | 
			
		||||
/* Sensible default limits for a 6LoWPAN-ND node */
 | 
			
		||||
static size_t rpl_purge_threshold = 1 * 1024;
 | 
			
		||||
static size_t rpl_alloc_limit = 2 * 1024; // 0 means no limit
 | 
			
		||||
static size_t rpl_purge_threshold = 2 * 1024;
 | 
			
		||||
static size_t rpl_alloc_limit = 4 * 1024; // 0 means no limit
 | 
			
		||||
 | 
			
		||||
static size_t rpl_alloc_total;
 | 
			
		||||
#define RPL_ALLOC_OVERHEAD 8
 | 
			
		||||
| 
						 | 
				
			
			@ -190,6 +190,10 @@ void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms)
 | 
			
		|||
{
 | 
			
		||||
    rpl_policy_set_initial_dao_ack_wait(timeout_in_ms);
 | 
			
		||||
}
 | 
			
		||||
void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size)
 | 
			
		||||
{
 | 
			
		||||
    rpl_policy_set_mrhof_parent_set_size(parent_set_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Send address registration to either specified address, or to non-registered address */
 | 
			
		||||
void rpl_control_register_address(protocol_interface_info_entry_t *interface, const uint8_t addr[16])
 | 
			
		||||
| 
						 | 
				
			
			@ -247,6 +251,56 @@ bool rpl_control_is_dodag_parent_candidate(protocol_interface_info_entry_t *inte
 | 
			
		|||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t rpl_control_candidate_list_size(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance)
 | 
			
		||||
{
 | 
			
		||||
    if (!interface->rpl_domain) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rpl_instance_address_candidate_count(rpl_instance, false);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t rpl_control_selected_parent_count(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance)
 | 
			
		||||
{
 | 
			
		||||
    if (!interface->rpl_domain) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rpl_instance_address_candidate_count(rpl_instance, true);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool rpl_control_probe_parent_candidate(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16])
 | 
			
		||||
{
 | 
			
		||||
    if (!interface->rpl_domain) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    // go through instances and parents and check if they match the address.
 | 
			
		||||
    ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) {
 | 
			
		||||
        if (rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool rpl_possible_better_candidate(struct protocol_interface_info_entry *interface, rpl_instance_t *rpl_instance, const uint8_t ll_addr[16], uint16_t candidate_rank, uint16_t etx)
 | 
			
		||||
{
 | 
			
		||||
    if (!interface->rpl_domain) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(rpl_instance, ll_addr, interface->id);
 | 
			
		||||
    if (!neighbour) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rpl_instance_possible_better_candidate(rpl_instance, neighbour, candidate_rank, etx);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t *interface, bool parent_list)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -266,6 +320,13 @@ uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t
 | 
			
		|||
    return parent_list_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_control_neighbor_delete_from_instance(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, const uint8_t ll_addr[16])
 | 
			
		||||
{
 | 
			
		||||
    rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id);
 | 
			
		||||
    if (neighbour) {
 | 
			
		||||
        rpl_delete_neighbour(instance, neighbour);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16])
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -274,14 +335,26 @@ void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, con
 | 
			
		|||
    }
 | 
			
		||||
    // go through instances and delete address.
 | 
			
		||||
    ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) {
 | 
			
		||||
 | 
			
		||||
        rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id);
 | 
			
		||||
        if (neighbour) {
 | 
			
		||||
            rpl_delete_neighbour(instance, neighbour);
 | 
			
		||||
        }
 | 
			
		||||
        rpl_control_neighbor_delete_from_instance(interface, instance, ll_addr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool rpl_control_find_worst_neighbor(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance, uint8_t ll_addr[static 16])
 | 
			
		||||
{
 | 
			
		||||
    if (!interface->rpl_domain) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rpl_neighbour_t *neighbour = rpl_lookup_last_candidate_from_list(rpl_instance);
 | 
			
		||||
    if (neighbour) {
 | 
			
		||||
        memcpy(ll_addr, rpl_neighbour_ll_address(neighbour), 16);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Address changes need to trigger DAO target re-evaluation */
 | 
			
		||||
static void rpl_control_addr_notifier(struct protocol_interface_info_entry *interface, const if_address_entry_t *addr, if_address_callback_t reason)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -307,19 +380,24 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte
 | 
			
		|||
 | 
			
		||||
static void rpl_control_etx_change_callback(int8_t  nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index)
 | 
			
		||||
{
 | 
			
		||||
    (void)previous_etx;
 | 
			
		||||
    (void)current_etx;
 | 
			
		||||
 | 
			
		||||
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id);
 | 
			
		||||
    if (!cur || !cur->rpl_domain) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    // ETX is "better" if now lower, or previous was "unknown" and new isn't infinite
 | 
			
		||||
    bool better = current_etx < previous_etx || (previous_etx == 0 && current_etx != 0xffff);
 | 
			
		||||
 | 
			
		||||
    rpl_domain_t *domain = cur->rpl_domain;
 | 
			
		||||
    uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain);
 | 
			
		||||
    tr_debug("Triggering parent selection due to ETX change on neigh index %u, etx %u", attribute_index, current_etx);
 | 
			
		||||
    tr_debug("Triggering parent selection due to ETX %s on neigh index %u, etx %u", better ? "better" : "worse", attribute_index, current_etx);
 | 
			
		||||
    rpl_dodag_t *dodag = NULL;
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
 | 
			
		||||
        rpl_instance_trigger_parent_selection(instance, delay);
 | 
			
		||||
        if (better) {
 | 
			
		||||
            dodag = rpl_instance_current_dodag(instance);
 | 
			
		||||
        }
 | 
			
		||||
        rpl_instance_trigger_parent_selection(instance, delay, dodag);
 | 
			
		||||
        if (rpl_instance_am_root(instance)) {
 | 
			
		||||
            rpl_downward_paths_invalidate(instance);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -339,6 +417,7 @@ rpl_domain_t *rpl_control_create_domain(void)
 | 
			
		|||
    domain->callback = NULL;
 | 
			
		||||
    domain->cb_handle = NULL;
 | 
			
		||||
    domain->force_leaf = false;
 | 
			
		||||
    domain->process_routes = true;
 | 
			
		||||
    ns_list_add_to_start(&rpl_domains, domain);
 | 
			
		||||
 | 
			
		||||
    addr_notification_register(rpl_control_addr_notifier);
 | 
			
		||||
| 
						 | 
				
			
			@ -495,9 +574,14 @@ rpl_dodag_t *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t instanc
 | 
			
		|||
 | 
			
		||||
    rpl_dodag_t *dodag = rpl_lookup_dodag(instance, dodagid);
 | 
			
		||||
    if (dodag) {
 | 
			
		||||
        if (rpl_dodag_am_root(dodag)) {
 | 
			
		||||
            tr_error("Root DODAG already exists");
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Delete non root information and recreate dodag
 | 
			
		||||
        rpl_delete_dodag(dodag);
 | 
			
		||||
    }
 | 
			
		||||
    dodag = rpl_create_dodag(instance, dodagid, g_mop_prf);
 | 
			
		||||
    if (!dodag) {
 | 
			
		||||
        tr_error("No mem for DODAG root");
 | 
			
		||||
| 
						 | 
				
			
			@ -547,13 +631,16 @@ void rpl_control_increment_dtsn(rpl_dodag_t *dodag)
 | 
			
		|||
    //rpl_dodag_inconsistency(dodag); currently implied by rpl_dodag_increment_dtsn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_control_increment_dodag_version(rpl_dodag_t *dodag)
 | 
			
		||||
uint8_t rpl_control_increment_dodag_version(rpl_dodag_t *dodag)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t new_version = 240;
 | 
			
		||||
    if (rpl_dodag_am_root(dodag)) {
 | 
			
		||||
        uint8_t new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag));
 | 
			
		||||
        new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag));
 | 
			
		||||
        rpl_dodag_set_version_number_as_root(dodag, new_version);
 | 
			
		||||
    }
 | 
			
		||||
    return new_version;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -586,6 +673,10 @@ void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
void rpl_control_process_routes(rpl_domain_t *domain, bool process_routes)
 | 
			
		||||
{
 | 
			
		||||
    domain->process_routes = process_routes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check whether the options section of a RPL control message is well-formed */
 | 
			
		||||
static bool rpl_control_options_well_formed(const uint8_t *dptr, uint_fast16_t dlen)
 | 
			
		||||
| 
						 | 
				
			
			@ -855,7 +946,6 @@ static void rpl_control_process_route_options(rpl_instance_t *instance, rpl_doda
 | 
			
		|||
        }
 | 
			
		||||
        rpl_dodag_update_dio_route(dodag, prefix, prefix_len, flags, lifetime, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* We do not purge unadvertised routes. Thus if the root wants to purge
 | 
			
		||||
     * a route before its lifetime is up, stopping advertising it is not
 | 
			
		||||
     * sufficient, it has to advertise it with low or zero lifetime. This fits
 | 
			
		||||
| 
						 | 
				
			
			@ -975,8 +1065,9 @@ malformed:
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Never listen to nodes in a DODAG we're rooting */
 | 
			
		||||
    if (rpl_dodag_am_root(dodag)) {
 | 
			
		||||
    /* Never listen to nodes in a DODAG we're rooting or were root*/
 | 
			
		||||
    if (rpl_dodag_am_root(dodag) ||
 | 
			
		||||
            rpl_dodag_was_root(dodag)) {
 | 
			
		||||
        /* TODO - if version is newer or unordered, increment our version to be higher? */
 | 
			
		||||
        /* Old code had this trick - actually, would need to go further. Want to listen first, then use a higher
 | 
			
		||||
         * than existing. */
 | 
			
		||||
| 
						 | 
				
			
			@ -1009,7 +1100,7 @@ malformed:
 | 
			
		|||
    const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag);
 | 
			
		||||
    if (!conf) {
 | 
			
		||||
        /* TODO - rate limit DIS? */
 | 
			
		||||
        if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle)) {
 | 
			
		||||
        if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) {
 | 
			
		||||
            goto invalid_parent;
 | 
			
		||||
        }
 | 
			
		||||
        rpl_control_transmit_dis(domain, cur, RPL_SOLINFO_PRED_DODAGID | RPL_SOLINFO_PRED_INSTANCEID, instance_id, dodagid, 0, buf->src_sa.address);
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,15 +1134,21 @@ malformed:
 | 
			
		|||
 | 
			
		||||
    /* Now we create the neighbour, if we don't already have a record */
 | 
			
		||||
    if (!neighbour) {
 | 
			
		||||
 | 
			
		||||
        if (domain->new_parent_add) {
 | 
			
		||||
 | 
			
		||||
            if (!domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) {
 | 
			
		||||
                goto invalid_parent;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        neighbour = rpl_create_neighbour(version, buf->src_sa.address, cur->id, g_mop_prf, dtsn);
 | 
			
		||||
        //Call Here new parent create
 | 
			
		||||
        if (!neighbour) {
 | 
			
		||||
            goto invalid_parent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle)) {
 | 
			
		||||
            goto invalid_parent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1182,7 +1279,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
 | 
			
		|||
    const rpl_dio_route_list_t *routes = rpl_dodag_get_route_list(dodag);
 | 
			
		||||
    const prefix_list_t *prefixes = rpl_dodag_get_prefix_list(dodag);
 | 
			
		||||
 | 
			
		||||
    tr_debug("transmit dio, rank: %x", rank);
 | 
			
		||||
    tr_info("transmit dio, rank: %x", rank);
 | 
			
		||||
    protocol_interface_info_entry_t *downstream_if = protocol_stack_interface_info_get_by_id(domain->non_storing_downstream_interface);
 | 
			
		||||
    length = 24;
 | 
			
		||||
    if (conf) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1770,12 +1867,24 @@ static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print
 | 
			
		|||
 | 
			
		||||
void rpl_control_print(route_print_fn_t *print_fn)
 | 
			
		||||
{
 | 
			
		||||
    print_fn("RPL memory usage %zu", rpl_alloc_total);
 | 
			
		||||
    unsigned t = protocol_core_monotonic_time % 10;
 | 
			
		||||
    unsigned s_full = protocol_core_monotonic_time / 10;
 | 
			
		||||
    unsigned m = s_full / 60;
 | 
			
		||||
    unsigned s = s_full % 60;
 | 
			
		||||
    unsigned h = m / 60;
 | 
			
		||||
    m %= 60;
 | 
			
		||||
    // %zu doesn't work on some Mbed toolchains
 | 
			
		||||
    print_fn("Time %02u:%02u:%02u.%u (%u.%u) RPL memory usage %" PRIu32, h, m, s, t, s_full, t, (uint32_t) rpl_alloc_total);
 | 
			
		||||
    ns_list_foreach(rpl_domain_t, domain, &rpl_domains) {
 | 
			
		||||
        rpl_domain_print(domain, print_fn);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain)
 | 
			
		||||
{
 | 
			
		||||
    return rpl_policy_mrhof_parent_set_size(domain);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef RPL_STRUCTURES_H_
 | 
			
		||||
#error "rpl_structures.h should not be included by rpl_control.c"
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,8 @@ typedef void rpl_domain_callback_t(rpl_event_t event, void *handle);
 | 
			
		|||
 | 
			
		||||
typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local);
 | 
			
		||||
 | 
			
		||||
typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle);
 | 
			
		||||
typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct rpl_domain {
 | 
			
		||||
    NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +55,8 @@ typedef struct rpl_domain {
 | 
			
		|||
    int8_t non_storing_downstream_interface;
 | 
			
		||||
    /* As part of shutdown, we can force entering leaf mode */
 | 
			
		||||
    bool force_leaf;
 | 
			
		||||
    /* if false routes are not set to routing table, instead default route is added for DODAGID */
 | 
			
		||||
    bool process_routes;
 | 
			
		||||
    rpl_domain_callback_t *callback;
 | 
			
		||||
    rpl_prefix_callback_t *prefix_cb;
 | 
			
		||||
    rpl_new_parent_callback_t *new_parent_add;
 | 
			
		||||
| 
						 | 
				
			
			@ -129,13 +132,15 @@ struct rpl_dodag *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t in
 | 
			
		|||
void rpl_control_delete_dodag_root(rpl_domain_t *domain, struct rpl_dodag *dodag);
 | 
			
		||||
void rpl_control_update_dodag_route(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, bool age);
 | 
			
		||||
void rpl_control_update_dodag_prefix(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool age);
 | 
			
		||||
void rpl_control_increment_dodag_version(struct rpl_dodag *dodag);
 | 
			
		||||
uint8_t rpl_control_increment_dodag_version(struct rpl_dodag *dodag);
 | 
			
		||||
void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf);
 | 
			
		||||
void rpl_control_set_dodag_pref(struct rpl_dodag *dodag, uint8_t pref);
 | 
			
		||||
void rpl_control_increment_dtsn(struct rpl_dodag *dodag);
 | 
			
		||||
 | 
			
		||||
/* Force leaf behaviour on a domain - useful before shutdown, and in conjunction with poison */
 | 
			
		||||
void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf);
 | 
			
		||||
/*Process routes from DIOs and add those as real routes. if routes are not processed assume DODAGID as default route*/
 | 
			
		||||
void rpl_control_process_routes(rpl_domain_t *domain, bool process_routes);
 | 
			
		||||
 | 
			
		||||
/* Manually send poison on all existing instances a few times */
 | 
			
		||||
void rpl_control_poison(rpl_domain_t *domain, uint8_t poison_count);
 | 
			
		||||
| 
						 | 
				
			
			@ -153,13 +158,21 @@ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[1
 | 
			
		|||
void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]);
 | 
			
		||||
bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]);
 | 
			
		||||
bool rpl_control_is_dodag_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint16_t candidate_cmp_limiter);
 | 
			
		||||
bool rpl_control_probe_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]);
 | 
			
		||||
bool rpl_possible_better_candidate(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, const uint8_t ll_addr[16], uint16_t candidate_rank, uint16_t etx);
 | 
			
		||||
uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list);
 | 
			
		||||
uint16_t rpl_control_candidate_list_size(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance);
 | 
			
		||||
uint16_t rpl_control_selected_parent_count(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance);
 | 
			
		||||
void rpl_control_neighbor_delete(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]);
 | 
			
		||||
void rpl_control_neighbor_delete_from_instance(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, const uint8_t ll_addr[16]);
 | 
			
		||||
bool rpl_control_find_worst_neighbor(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, uint8_t ll_addr[16]);
 | 
			
		||||
 | 
			
		||||
/* Parent link confirmation API extension */
 | 
			
		||||
void rpl_control_request_parent_link_confirmation(bool requested);
 | 
			
		||||
void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count);
 | 
			
		||||
void rpl_control_set_dao_retry_count(uint8_t count);
 | 
			
		||||
void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms);
 | 
			
		||||
void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size);
 | 
			
		||||
void rpl_control_register_address(struct protocol_interface_info_entry *interface, const uint8_t addr[16]);
 | 
			
		||||
void rpl_control_address_register_done(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t status);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -176,6 +189,7 @@ bool rpl_control_read_dodag_info(const struct rpl_instance *instance, struct rpl
 | 
			
		|||
const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_instance *instance);
 | 
			
		||||
const uint8_t *rpl_control_preferred_parent_addr(const struct rpl_instance *instance, bool global);
 | 
			
		||||
uint16_t rpl_control_current_rank(const struct rpl_instance *instance);
 | 
			
		||||
uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain);
 | 
			
		||||
 | 
			
		||||
#else /* HAVE_RPL */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -185,6 +199,8 @@ uint16_t rpl_control_current_rank(const struct rpl_instance *instance);
 | 
			
		|||
#define rpl_control_free_domain_instances_from_interface(cur) ((void) 0)
 | 
			
		||||
#define rpl_control_register_address(interface, addr) ((void) 0)
 | 
			
		||||
#define rpl_control_address_register_done(interface, ll_addr, status) ((void) 0)
 | 
			
		||||
#define rpl_policy_mrhof_parent_set_size_get(domain) (0)
 | 
			
		||||
#define rpl_control_set_mrhof_parent_set_size(parent_set_size)
 | 
			
		||||
 | 
			
		||||
#endif /* HAVE_RPL */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -545,8 +545,7 @@ retry:
 | 
			
		|||
             */
 | 
			
		||||
            ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
 | 
			
		||||
                if (neighbour->dao_path_control & unassigned_pc) {
 | 
			
		||||
                    unassigned_pc &= neighbour->dao_path_control;
 | 
			
		||||
                    *path_control = unassigned_pc;
 | 
			
		||||
                    *path_control = neighbour->dao_path_control;
 | 
			
		||||
                    *parent = neighbour;
 | 
			
		||||
                    return target;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -561,14 +560,7 @@ retry:
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* If looking for a follow-up target, final path control must match */
 | 
			
		||||
        if (t1) {
 | 
			
		||||
            if (unassigned_pc != *path_control) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            *path_control = unassigned_pc;
 | 
			
		||||
        }
 | 
			
		||||
        *path_control = target->path_control;
 | 
			
		||||
        return target;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1786,7 +1778,7 @@ static bool rpl_instance_push_address_registration(protocol_interface_info_entry
 | 
			
		|||
    if (!buf) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    tr_debug("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address));
 | 
			
		||||
    tr_info("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address));
 | 
			
		||||
    protocol_push(buf);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1811,6 +1803,8 @@ static void rpl_instance_address_registration_cancel(rpl_instance_t *instance)
 | 
			
		|||
    instance->wait_response = NULL;
 | 
			
		||||
    instance->pending_neighbour_confirmation = false;
 | 
			
		||||
    instance->delay_dao_timer = 0;
 | 
			
		||||
    instance->dao_in_transit = false;
 | 
			
		||||
    instance->dao_retry_timer = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_instance_parent_address_reg_timer_update(rpl_instance_t *instance, uint16_t seconds)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,12 +45,14 @@
 | 
			
		|||
static void rpl_mrhof_parent_selection(rpl_instance_t *instance);
 | 
			
		||||
static uint16_t rpl_mrhof_path_cost_through_neighbour(const rpl_neighbour_t *neighbour);
 | 
			
		||||
static bool rpl_mrhof_neighbour_acceptable(const rpl_instance_t *instance, const rpl_neighbour_t *neighbour);
 | 
			
		||||
static bool rpl_mrhof_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx);
 | 
			
		||||
 | 
			
		||||
static rpl_objective_t rpl_mrhof = {
 | 
			
		||||
    .ocp = RPL_OCP_MRHOF,
 | 
			
		||||
    .parent_selection = rpl_mrhof_parent_selection,
 | 
			
		||||
    .path_cost = rpl_mrhof_path_cost_through_neighbour,
 | 
			
		||||
    .neighbour_acceptable = rpl_mrhof_neighbour_acceptable,
 | 
			
		||||
    .possible_better_candidate = rpl_mrhof_possible_better_candidate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct rpl_of0_params {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +96,26 @@ static bool rpl_mrhof_neighbour_acceptable(const rpl_instance_t *instance, const
 | 
			
		|||
    return rpl_mrhof_link_metric_to_neighbour(neighbour) <= rpl_policy_mrhof_max_link_metric(instance->domain);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool rpl_mrhof_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t existing_path = rpl_mrhof_path_cost_through_neighbour(existing);
 | 
			
		||||
    // Optimistically assume we could get a perfect link to this new person
 | 
			
		||||
    // But add hysteresis to avoid switching unless potentially worthwhile
 | 
			
		||||
    // (Compare rpl_mrhof_etx which assumes poor for unknown as a sort of hysteresis)
 | 
			
		||||
    // Think: could actually use rpl_mrhof_etx here to get an existing ETX estimate
 | 
			
		||||
    // (except that gives infinite if no current link, would want a variant that checks
 | 
			
		||||
    // blacklist records for remembered poor ETX)
 | 
			
		||||
    uint16_t threshold = rpl_policy_mrhof_parent_switch_threshold(instance->domain);
 | 
			
		||||
    if (etx == 0) {
 | 
			
		||||
        etx = 128;
 | 
			
		||||
    } else if (etx >= (0xffff - threshold)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    etx += threshold;
 | 
			
		||||
    uint16_t potential_path_with_hysteresis = rpl_rank_add(rank, etx);
 | 
			
		||||
    return potential_path_with_hysteresis <= existing_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Given a preferred parent, we are only permitted to stretch our above the
 | 
			
		||||
 * path cost through that parent by a certain (policy) amount to accommodate a
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,9 +28,12 @@ typedef struct rpl_objective {
 | 
			
		|||
    uint16_t ocp;
 | 
			
		||||
    /* Run the parent selection algorithm - see rpl_of0.c for detailed info */
 | 
			
		||||
    void (*parent_selection)(struct rpl_instance *);
 | 
			
		||||
    /* Return the path cost of a neighbour (for debug prints only) */
 | 
			
		||||
    /* Return the path cost of a neighbour */
 | 
			
		||||
    uint16_t (*path_cost)(const struct rpl_neighbour *);
 | 
			
		||||
    bool (*neighbour_acceptable)(const struct rpl_instance *, const struct rpl_neighbour *);
 | 
			
		||||
    /* Could someone with specified rank be a significantly better candidate than the existing one? */
 | 
			
		||||
    /* (In future, this API could be extended to pass a metric pointer as well as rank) */
 | 
			
		||||
    bool (*possible_better_candidate)(const struct rpl_instance *, const struct rpl_neighbour *existing, uint16_t rank, uint16_t etx);
 | 
			
		||||
    ns_list_link_t link;
 | 
			
		||||
} rpl_objective_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,12 +42,14 @@
 | 
			
		|||
static void rpl_of0_parent_selection(rpl_instance_t *instance);
 | 
			
		||||
static uint16_t rpl_of0_rank_through_neighbour(const rpl_neighbour_t *neighbour);
 | 
			
		||||
static bool rpl_of0_neighbour_acceptable(const rpl_instance_t *instance, const rpl_neighbour_t *neighbour);
 | 
			
		||||
static bool rpl_of0_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx);
 | 
			
		||||
 | 
			
		||||
static rpl_objective_t rpl_of0 = {
 | 
			
		||||
    .ocp = RPL_OCP_OF0,
 | 
			
		||||
    .parent_selection = rpl_of0_parent_selection,
 | 
			
		||||
    .path_cost = rpl_of0_rank_through_neighbour,
 | 
			
		||||
    .neighbour_acceptable = rpl_of0_neighbour_acceptable,
 | 
			
		||||
    .possible_better_candidate = rpl_of0_possible_better_candidate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_STEP_OF_RANK 3
 | 
			
		||||
| 
						 | 
				
			
			@ -115,6 +117,14 @@ static uint16_t rpl_of0_rank_through_neighbour(const rpl_neighbour_t *neighbour)
 | 
			
		|||
    return rpl_rank_add(neighbour->rank, rpl_of0_rank_increase(neighbour));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool rpl_of0_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx)
 | 
			
		||||
{
 | 
			
		||||
    (void)etx;
 | 
			
		||||
    uint16_t existing_path = rpl_of0_rank_through_neighbour(existing);
 | 
			
		||||
    uint16_t potential_path_with_hysteresis = rpl_rank_add(rank, 2 * rpl_policy_of0_rank_factor(instance->domain) * existing->dodag_version->dodag->config.min_hop_rank_increase);
 | 
			
		||||
    return potential_path_with_hysteresis <= existing_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Given a preferred parent, we are only permitted to stretch our above the
 | 
			
		||||
 * path cost through that parent by a certain (policy) amount to accommodate a
 | 
			
		||||
 * bigger parent set.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ static int8_t rpl_policy_dao_retry_count_conf = 0;
 | 
			
		|||
static int16_t rpl_policy_dao_initial_timeout_conf = 20; // Default is 2 seconds 100ms ticks
 | 
			
		||||
static uint16_t rpl_policy_dio_validity_period_hysteresis = 0x0180; //Fixed Point 1.5
 | 
			
		||||
static uint8_t rpl_policy_multicast_config_min_advertisment_count = 0;
 | 
			
		||||
 | 
			
		||||
static uint8_t rpl_policy_mrhof_parent_set_size_conf = 3; // default parent set size
 | 
			
		||||
 | 
			
		||||
/* TODO - application API to control when to join new instances / DODAGs
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ int8_t rpl_policy_dao_retry_count()
 | 
			
		|||
/* Given the next-hop address from a source routing header, which interface,
 | 
			
		||||
 * if any, should we assume that next hop is on?
 | 
			
		||||
 */
 | 
			
		||||
#define ETX_SRH_THRESHOLD 0x800 /* 8.8 fixed-point, so 4 */
 | 
			
		||||
#define ETX_SRH_THRESHOLD 0x400 /* 8.8 fixed-point, so 4 */
 | 
			
		||||
int8_t rpl_policy_srh_next_hop_interface(rpl_domain_t *domain, int8_t if_id, const uint8_t *next_hop)
 | 
			
		||||
{
 | 
			
		||||
    if (domain->non_storing_downstream_interface != -1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -326,11 +326,16 @@ uint_fast8_t rpl_policy_of0_max_backup_successors(const rpl_domain_t *domain)
 | 
			
		|||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_policy_set_mrhof_parent_set_size(uint8_t parent_set_size)
 | 
			
		||||
{
 | 
			
		||||
    rpl_policy_mrhof_parent_set_size_conf = parent_set_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain)
 | 
			
		||||
{
 | 
			
		||||
    (void)domain;
 | 
			
		||||
 | 
			
		||||
    return 3;
 | 
			
		||||
    return rpl_policy_mrhof_parent_set_size_conf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t rpl_policy_mrhof_max_rank_stretch_for_extra_parents(const rpl_domain_t *domain)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ uint_fast8_t rpl_policy_of0_rank_factor(const rpl_domain_t *domain);
 | 
			
		|||
bool rpl_policy_of0_dodag_preference_supersedes_grounded(const rpl_domain_t *domain);
 | 
			
		||||
uint_fast8_t rpl_policy_of0_max_backup_successors(const rpl_domain_t *domain);
 | 
			
		||||
 | 
			
		||||
void rpl_policy_set_mrhof_parent_set_size(uint8_t parent_set_size);
 | 
			
		||||
uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain);
 | 
			
		||||
uint16_t rpl_policy_mrhof_max_link_metric(const rpl_domain_t *domain);
 | 
			
		||||
uint16_t rpl_policy_mrhof_parent_switch_threshold(const rpl_domain_t *domain);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,10 +32,6 @@
 | 
			
		|||
struct rpl_objective;
 | 
			
		||||
 | 
			
		||||
/* Descriptor for a RPL neighbour within a DODAG
 | 
			
		||||
 *
 | 
			
		||||
 * The neighbour is normally associated with a DODAG Version, but may not be,
 | 
			
		||||
 * if the version has been retired, and we haven't since heard from that
 | 
			
		||||
 * neighbour. In that case dodag_version is NULL.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that global address is only needed with downward routes, but I don't
 | 
			
		||||
 * think it's worth optimising for an "upward-only" build. (Unless to be a RPL
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +41,7 @@ struct rpl_objective;
 | 
			
		|||
 * first in the instance candidate_neighbour list, in order of preference.
 | 
			
		||||
 */
 | 
			
		||||
struct rpl_neighbour {
 | 
			
		||||
    rpl_dodag_version_t *dodag_version;     // Back pointer to DODAG Version (may be NULL, if not dodag_parent)
 | 
			
		||||
    rpl_dodag_version_t *dodag_version;     // Back pointer to DODAG Version
 | 
			
		||||
    uint8_t ll_address[16];                 // Link-local address (source of DIO)
 | 
			
		||||
    uint8_t global_address[16];             // Global address (from DIO RIO)
 | 
			
		||||
    bool dodag_parent: 1;                   // This is a DODAG parent (if true, dodag_version may not be NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,10 +83,11 @@ struct rpl_dodag {
 | 
			
		|||
    rpl_dodag_conf_t config;                        /* Configuration from DIO */
 | 
			
		||||
    uint8_t info_version;                           /* Version for g_mop_prf and config */
 | 
			
		||||
    bool root: 1;                                   /* We are the root of this DODAG */
 | 
			
		||||
    bool was_root: 1;                               /* If we have ever been a root in this DODAG */
 | 
			
		||||
    bool leaf: 1;                                   /* We are a leaf in this DODAG (by policy) */
 | 
			
		||||
    bool have_config: 1;                            /* We have the config */
 | 
			
		||||
    bool used: 1;                                   /* We have ever been a member of this DODAG? */
 | 
			
		||||
    uint8_t new_config_advertisment_count;      /* We have advertiment new config at multicasti DIO */
 | 
			
		||||
    uint8_t new_config_advertisment_count;          /* We have advertiment new config at multicasti DIO  max updated value is 0xfe*/
 | 
			
		||||
    NS_LIST_HEAD(rpl_dodag_version_t, link) versions; /* List of DODAG versions (newest first) */
 | 
			
		||||
    prefix_list_t prefixes;                         /* Prefixes advertised in DIO PIOs */
 | 
			
		||||
    rpl_dio_route_list_t routes;                    /* Routes advertised in DIO RIOs*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,6 +74,8 @@ static NS_LIST_DEFINE(rpl_candidate_neighbour_set, rpl_neighbour_t, candidate_ne
 | 
			
		|||
static void rpl_instance_remove_parents(rpl_instance_t *instance);
 | 
			
		||||
static void rpl_instance_remove_system_routes_through_parent(rpl_instance_t *instance, rpl_neighbour_t *parent);
 | 
			
		||||
static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *route);
 | 
			
		||||
static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t *instance);
 | 
			
		||||
static uint32_t rpl_dio_imax_time_calculate(uint16_t Imax, uint16_t fixed_point);
 | 
			
		||||
 | 
			
		||||
/* Rank comparison, and DAGRank(rank) */
 | 
			
		||||
uint16_t nrpl_dag_rank(const rpl_dodag_t *dodag, uint16_t rank)
 | 
			
		||||
| 
						 | 
				
			
			@ -283,6 +285,16 @@ rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance)
 | 
			
		|||
    return neighbour;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t rpl_instance_candidate_rank(const rpl_neighbour_t *candidate)
 | 
			
		||||
{
 | 
			
		||||
    return candidate->rank;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool rpl_instance_possible_better_candidate(const rpl_instance_t *instance, rpl_neighbour_t *replacing, uint16_t candidate_rank, uint16_t etx)
 | 
			
		||||
{
 | 
			
		||||
    return instance->of->possible_better_candidate(instance, replacing, candidate_rank, etx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* If we're a member of a DODAG Version matching the predicate in this instance,
 | 
			
		||||
 * return it. Mainly used for handling DODAG Information Solicitations.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -340,10 +352,19 @@ void rpl_instance_force_leaf(rpl_instance_t *instance)
 | 
			
		|||
    instance->current_rank = RPL_RANK_INFINITE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay)
 | 
			
		||||
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay, rpl_dodag_t *dodag)
 | 
			
		||||
{
 | 
			
		||||
    /* When "improving", let us have a minimum trigger time based on Imin, for large networks */
 | 
			
		||||
    if (dodag) {
 | 
			
		||||
        //Convert imin 100ms tick to seconds
 | 
			
		||||
        uint16_t i_min_delay = dodag->dio_timer_params.Imin / 10;
 | 
			
		||||
        if (i_min_delay > delay) {
 | 
			
		||||
            delay = i_min_delay;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (instance->parent_selection_timer == 0 || instance->parent_selection_timer > delay) {
 | 
			
		||||
        instance->parent_selection_timer = randLIB_randomise_base(delay, 0x7333, 0x8CCD) /* +/- 10% */;
 | 
			
		||||
        instance->parent_selection_timer = randLIB_randomise_base(delay, 0x8000, 0x999A) /* Random between delay * 1.0-1.2 */;
 | 
			
		||||
        tr_debug("Timed parent triggered %u", instance->parent_selection_timer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -390,6 +411,15 @@ rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instan
 | 
			
		|||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl_neighbour_t *rpl_lookup_last_candidate_from_list(const rpl_instance_t *instance)
 | 
			
		||||
{
 | 
			
		||||
    rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance);
 | 
			
		||||
    if (neighbour && neighbour->considered && !neighbour->dodag_parent) {
 | 
			
		||||
        return neighbour;
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *version, const uint8_t *addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn)
 | 
			
		||||
{
 | 
			
		||||
    /* Should gate higher-rank neighbours here - ignore higher-rank neighbours
 | 
			
		||||
| 
						 | 
				
			
			@ -563,7 +593,7 @@ void rpl_delete_dodag_version(rpl_dodag_version_t *version)
 | 
			
		|||
        // triggering poison immediately.
 | 
			
		||||
        // Give parent selection a chance to select another version (but will it have any info on-hand?)
 | 
			
		||||
        instance->current_dodag_version = NULL;
 | 
			
		||||
        rpl_instance_trigger_parent_selection(instance, 5);
 | 
			
		||||
        rpl_instance_trigger_parent_selection(instance, 5, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
 | 
			
		||||
| 
						 | 
				
			
			@ -638,6 +668,7 @@ rpl_dodag_t *rpl_create_dodag(rpl_instance_t *instance, const uint8_t *dodagid,
 | 
			
		|||
    memcpy(dodag->id, dodagid, 16);
 | 
			
		||||
    dodag->leaf = false;
 | 
			
		||||
    dodag->root = false;
 | 
			
		||||
    dodag->was_root = false;
 | 
			
		||||
    dodag->have_config = false;
 | 
			
		||||
    dodag->used = false;
 | 
			
		||||
    dodag->g_mop_prf = g_mop_prf;
 | 
			
		||||
| 
						 | 
				
			
			@ -678,15 +709,9 @@ void rpl_delete_dodag_root(rpl_dodag_t *dodag)
 | 
			
		|||
{
 | 
			
		||||
    // This should trigger immediate poison
 | 
			
		||||
    rpl_instance_set_dodag_version(dodag->instance, NULL, RPL_RANK_INFINITE);
 | 
			
		||||
    // Deleting DODAG is not ideal - we will just pick up adverts from our
 | 
			
		||||
    // former children, and recreate, possibly violating the MaxRankIncrease.
 | 
			
		||||
    // Should retain DODAG version info and just unset root flag, which will
 | 
			
		||||
    // limit what happens when we hear adverts.
 | 
			
		||||
    // Problem is rpl_control_create_dodag_root which can't handle the
 | 
			
		||||
    // case where DODAG already exists. This would always be a problem if
 | 
			
		||||
    // we'd heard adverts in between delete and create, but would be an instant
 | 
			
		||||
    // problem without this delete. Need to fix.
 | 
			
		||||
    rpl_delete_dodag(dodag);
 | 
			
		||||
    // Retain DODAG version info and just unset root flag
 | 
			
		||||
    // We have was_root still set which will drop adverts for this dodag.
 | 
			
		||||
    dodag->root = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert RPL configuration to generic trickle parameters. Returns true if
 | 
			
		||||
| 
						 | 
				
			
			@ -792,6 +817,7 @@ void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root)
 | 
			
		|||
        dodag->root = root;
 | 
			
		||||
        if (root) {
 | 
			
		||||
            rpl_instance_remove_parents(dodag->instance);
 | 
			
		||||
            dodag->was_root = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            rpl_instance_run_parent_selection(dodag->instance);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -803,6 +829,11 @@ bool rpl_dodag_am_root(const rpl_dodag_t *dodag)
 | 
			
		|||
{
 | 
			
		||||
    return dodag->root;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool rpl_dodag_was_root(const rpl_dodag_t *dodag)
 | 
			
		||||
{
 | 
			
		||||
    return dodag->was_root;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void rpl_dodag_set_leaf(rpl_dodag_t *dodag, bool leaf)
 | 
			
		||||
| 
						 | 
				
			
			@ -1163,10 +1194,20 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t
 | 
			
		|||
{
 | 
			
		||||
    rpl_neighbour_t *worst = NULL;
 | 
			
		||||
    bool worst_acceptable = false;
 | 
			
		||||
    bool worst_old = false;
 | 
			
		||||
 | 
			
		||||
    /* Parents will be first - loop backwards so we take non-parents first */
 | 
			
		||||
    ns_list_foreach_reverse(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
 | 
			
		||||
        bool acceptable = instance->of->neighbour_acceptable(instance, neighbour);
 | 
			
		||||
        bool old;
 | 
			
		||||
        if (!neighbour->dodag_version) {
 | 
			
		||||
            old = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            uint32_t age = protocol_core_monotonic_time - neighbour->dio_timestamp;
 | 
			
		||||
            uint32_t age_threshold = rpl_dio_imax_time_calculate(neighbour->dodag_version->dodag->dio_timer_params.Imax,
 | 
			
		||||
                                                                 rpl_policy_dio_validity_period(instance->domain));
 | 
			
		||||
            old = age > age_threshold;
 | 
			
		||||
        }
 | 
			
		||||
        if (!worst) {
 | 
			
		||||
            goto new_worst;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1176,6 +1217,13 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t
 | 
			
		|||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Prefer neighbours with DODAG version */
 | 
			
		||||
        if (neighbour->dodag_version && !worst->dodag_version) {
 | 
			
		||||
            continue;
 | 
			
		||||
        } else if (!neighbour->dodag_version && worst->dodag_version) {
 | 
			
		||||
            goto new_worst;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Prefer to purge "unacceptable" neighbours according to OF */
 | 
			
		||||
        if (acceptable && !worst_acceptable) {
 | 
			
		||||
            continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -1183,18 +1231,24 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t
 | 
			
		|||
            goto new_worst;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Prefer to purge least-recently-heard-from */
 | 
			
		||||
        uint32_t neighbour_age = protocol_core_monotonic_time - neighbour->dio_timestamp;
 | 
			
		||||
        uint32_t worst_age = protocol_core_monotonic_time - worst->dio_timestamp;
 | 
			
		||||
        if (neighbour_age <= worst_age) {
 | 
			
		||||
        /* Prefer to purge old neighbours */
 | 
			
		||||
        if (old && !worst_old) {
 | 
			
		||||
            continue;
 | 
			
		||||
        } else {
 | 
			
		||||
        } else if (!old && worst_old) {
 | 
			
		||||
            goto new_worst;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Tiebreak by path cost, assuming we have dodag_version */
 | 
			
		||||
        if (neighbour->dodag_version && instance->of) {
 | 
			
		||||
            /* worst must also have version to reach this tiebreak */
 | 
			
		||||
            if (instance->of->path_cost(neighbour) <= instance->of->path_cost(worst)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
new_worst:
 | 
			
		||||
        worst = neighbour;
 | 
			
		||||
        worst_acceptable = acceptable;
 | 
			
		||||
        worst_old = old;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return worst;
 | 
			
		||||
| 
						 | 
				
			
			@ -1225,24 +1279,19 @@ bool rpl_instance_purge(rpl_instance_t *instance)
 | 
			
		|||
     */
 | 
			
		||||
    rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance);
 | 
			
		||||
    if (neighbour && neighbour->considered && !neighbour->dodag_parent && neighbour->dao_path_control == 0) {
 | 
			
		||||
        tr_debug("Candidate Purge: Remove %s", trace_ipv6(neighbour->ll_address));
 | 
			
		||||
        rpl_delete_neighbour(instance, neighbour);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag)
 | 
			
		||||
void rpl_instance_neighbours_changed(rpl_instance_t *instance, rpl_dodag_t *dodag)
 | 
			
		||||
{
 | 
			
		||||
    instance->neighbours_changed = true;
 | 
			
		||||
    uint16_t delay = rpl_policy_dio_parent_selection_delay(instance->domain);
 | 
			
		||||
    if (dodag) {
 | 
			
		||||
        //Convert imin 100ms tick to seconds
 | 
			
		||||
        uint16_t i_min_delay = dodag->dio_timer_params.Imin / 10;
 | 
			
		||||
        if (i_min_delay > delay) {
 | 
			
		||||
            delay = i_min_delay;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    rpl_instance_trigger_parent_selection(instance, delay);
 | 
			
		||||
 | 
			
		||||
    rpl_instance_trigger_parent_selection(instance, delay, dodag);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rpl_instance_remove_parents(rpl_instance_t *instance)
 | 
			
		||||
| 
						 | 
				
			
			@ -1315,6 +1364,10 @@ void rpl_dodag_update_implicit_system_routes(rpl_dodag_t *dodag, rpl_neighbour_t
 | 
			
		|||
    /* Also add a specific route to the DODAGID */
 | 
			
		||||
    ipv6_route_add_metric(dodag->id, 128, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric);
 | 
			
		||||
 | 
			
		||||
    /* Check if we assume default route to DODAGID */
 | 
			
		||||
    if (!dodag->instance->domain->process_routes) {
 | 
			
		||||
        ipv6_route_add_metric(NULL, 0, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called when a DIO RIO route has been updated (but not the parent list) */
 | 
			
		||||
| 
						 | 
				
			
			@ -1323,9 +1376,13 @@ static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *r
 | 
			
		|||
    if (!rpl_dodag_is_current(dodag)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rpl_instance_t *instance = dodag->instance;
 | 
			
		||||
 | 
			
		||||
    if (!instance->domain->process_routes) {
 | 
			
		||||
        // We dont add actual routes and only create default route throuh DODAGID
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
 | 
			
		||||
        if (neighbour->dodag_parent) {
 | 
			
		||||
            rpl_instance_update_system_dio_route(instance, neighbour, route);
 | 
			
		||||
| 
						 | 
				
			
			@ -1340,6 +1397,11 @@ static void rpl_instance_update_system_routes_through_parent(rpl_instance_t *ins
 | 
			
		|||
 | 
			
		||||
    rpl_dodag_update_implicit_system_routes(dodag, parent);
 | 
			
		||||
 | 
			
		||||
    if (!instance->domain->process_routes) {
 | 
			
		||||
        // We dont add actual routes and only create default route through DODAGID
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Then add the specific routes listed in the DIO as ROUTE_RPL_DIO */
 | 
			
		||||
    ns_list_foreach(rpl_dio_route_t, route, &dodag->routes) {
 | 
			
		||||
        rpl_instance_update_system_dio_route(instance, parent, route);
 | 
			
		||||
| 
						 | 
				
			
			@ -1381,13 +1443,15 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance)
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (instance->current_dodag_version && instance->current_dodag_version->dodag->root) {
 | 
			
		||||
    if (instance->current_dodag_version &&
 | 
			
		||||
            (instance->current_dodag_version->dodag->root || instance->current_dodag_version->dodag->was_root)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) {
 | 
			
		||||
        //Remove a Parent candidates which are not heared a long time ago and not slected ones
 | 
			
		||||
        if (!n->dodag_parent && (rpl_aged_lifetime(rpl_default_lifetime(n->dodag_version->dodag), n->dio_timestamp) == 0)) {
 | 
			
		||||
            tr_debug("Candidate timeout: Remove %s", trace_ipv6(n->ll_address));
 | 
			
		||||
            rpl_delete_neighbour(instance, n);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1429,7 +1493,7 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance)
 | 
			
		|||
    if (original_preferred != preferred_parent) {
 | 
			
		||||
        protocol_stats_update(STATS_RPL_PARENT_CHANGE, 1);
 | 
			
		||||
        if (preferred_parent) {
 | 
			
		||||
            tr_debug("New preferred parent %s", trace_array(preferred_parent->ll_address, 16));
 | 
			
		||||
            tr_info("New preferred parent %s", trace_array(preferred_parent->ll_address, 16));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1479,6 +1543,7 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance)
 | 
			
		|||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (!instance->of->neighbour_acceptable(instance, n)) {
 | 
			
		||||
            tr_debug("Candidate not acceptable: Remove %s", trace_ipv6(n->ll_address));
 | 
			
		||||
            rpl_delete_neighbour(instance, n);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1560,7 +1625,9 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_
 | 
			
		|||
        conf = &dodag->config;
 | 
			
		||||
    } else if (dodag->new_config_advertisment_count < rpl_policy_dio_multicast_config_advertisment_min_count()) {
 | 
			
		||||
        conf = &dodag->config;
 | 
			
		||||
        if (dodag->new_config_advertisment_count < 0xfe) {
 | 
			
		||||
            dodag->new_config_advertisment_count++;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        conf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1699,7 +1766,7 @@ bool rpl_instance_address_is_candidate(rpl_instance_t *instance, const uint8_t *
 | 
			
		|||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents)
 | 
			
		||||
uint16_t rpl_instance_address_candidate_count(const rpl_instance_t *instance, bool selected_parents)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t parent_list = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1717,7 +1784,6 @@ uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool sel
 | 
			
		|||
    return parent_list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1767,18 +1833,22 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks)
 | 
			
		|||
    if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    /* 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 (!instance->last_advertised_dodag_version && rpl_policy_parent_confirmation_requested()) {
 | 
			
		||||
        // We dont have any valid address in interface
 | 
			
		||||
        if (ns_list_count(&instance->dao_targets) == 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        /* Address registrations for parent ongoing*/
 | 
			
		||||
    if (rpl_policy_parent_confirmation_requested() && instance->pending_neighbour_confirmation) {
 | 
			
		||||
        if (instance->pending_neighbour_confirmation) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        /* If we are waiting for DAO or DAO registration is needed we dont send periodic DIOs */
 | 
			
		||||
        if (instance->dao_in_transit || instance->delay_dao_timer > 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (trickle_timer(&instance->dio_timer, &dodag->dio_timer_params, ticks)) {
 | 
			
		||||
        instance->dio_not_consistent = false;
 | 
			
		||||
        rpl_instance_dio_trigger(instance, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,7 @@ bool rpl_instance_am_root(const rpl_instance_t *instance);
 | 
			
		|||
uint8_t rpl_instance_mop(const rpl_instance_t *instance);
 | 
			
		||||
rpl_dodag_version_t *rpl_instance_current_dodag_version(const rpl_instance_t *instance);
 | 
			
		||||
rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance);
 | 
			
		||||
bool rpl_instance_possible_better_candidate(const rpl_instance_t *instance, rpl_neighbour_t *replacing, uint16_t candidate_rank, uint16_t etx);
 | 
			
		||||
rpl_dodag_version_t *rpl_instance_predicate_match(rpl_instance_t *instance, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, uint8_t version_num);
 | 
			
		||||
void rpl_instance_inconsistency(rpl_instance_t *instance);
 | 
			
		||||
void rpl_instance_consistent_rx(rpl_instance_t *instance);
 | 
			
		||||
| 
						 | 
				
			
			@ -77,15 +78,16 @@ void rpl_instance_increment_dtsn(rpl_instance_t *instance);
 | 
			
		|||
void rpl_dodag_set_pref(rpl_dodag_t *dodag, uint8_t pref);
 | 
			
		||||
void rpl_instance_poison(rpl_instance_t *instance, uint8_t count);
 | 
			
		||||
void rpl_instance_force_leaf(rpl_instance_t *instance);
 | 
			
		||||
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay);
 | 
			
		||||
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay, rpl_dodag_t *dodag);
 | 
			
		||||
void rpl_instance_remove_interface(rpl_instance_t *instance, int8_t if_id);
 | 
			
		||||
void rpl_instance_dio_trigger(rpl_instance_t *instance, struct protocol_interface_info_entry *cur, const uint8_t *addr);
 | 
			
		||||
void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair);
 | 
			
		||||
bool rpl_instance_local_repair(const rpl_instance_t *instance);
 | 
			
		||||
uint16_t rpl_instance_current_rank(const rpl_instance_t *instance);
 | 
			
		||||
uint16_t rpl_instance_candidate_rank(const rpl_neighbour_t *candidate);
 | 
			
		||||
bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr);
 | 
			
		||||
bool rpl_instance_address_is_candidate(rpl_instance_t *instance, const uint8_t *ipv6_addr, uint16_t candidate_amount);
 | 
			
		||||
uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents);
 | 
			
		||||
uint16_t rpl_instance_address_candidate_count(const rpl_instance_t *instance, bool selected_parents);
 | 
			
		||||
void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr);
 | 
			
		||||
void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +99,10 @@ uint8_t rpl_dodag_mop(const rpl_dodag_t *dodag);
 | 
			
		|||
void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root);
 | 
			
		||||
#ifdef HAVE_RPL_ROOT
 | 
			
		||||
bool rpl_dodag_am_root(const rpl_dodag_t *dodag);
 | 
			
		||||
bool rpl_dodag_was_root(const rpl_dodag_t *dodag);
 | 
			
		||||
#else
 | 
			
		||||
#define rpl_dodag_am_root(dodag) false
 | 
			
		||||
#define rpl_dodag_was_root(dodag) false
 | 
			
		||||
#endif
 | 
			
		||||
uint8_t rpl_dodag_get_version_number_as_root(const rpl_dodag_t *dodag);
 | 
			
		||||
void rpl_dodag_set_version_number_as_root(rpl_dodag_t *dodag, uint8_t number);
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +135,7 @@ void rpl_dodag_version_raise_greediness(rpl_dodag_version_t *version, uint16_t p
 | 
			
		|||
bool rpl_dodag_version_rank_indicates_possible_sub_dodag(const rpl_dodag_version_t *version, uint16_t rank);
 | 
			
		||||
 | 
			
		||||
rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instance, const uint8_t *addr, int8_t if_id);
 | 
			
		||||
rpl_neighbour_t *rpl_lookup_last_candidate_from_list(const rpl_instance_t *instance);
 | 
			
		||||
rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *instance, const uint8_t *ll_addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn);
 | 
			
		||||
void rpl_delete_neighbour(rpl_instance_t *instance, rpl_neighbour_t *neighbour);
 | 
			
		||||
bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_t *conf, const uint8_t *src, bool *become_leaf);
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +147,7 @@ bool rpl_neighbour_update_dtsn(rpl_neighbour_t *neighbour, uint8_t dtsn);
 | 
			
		|||
rpl_instance_t *rpl_neighbour_instance(const rpl_neighbour_t *neighbour);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag);
 | 
			
		||||
void rpl_instance_neighbours_changed(rpl_instance_t *instance, rpl_dodag_t *dodag);
 | 
			
		||||
void rpl_instance_run_parent_selection(rpl_instance_t *instance);
 | 
			
		||||
 | 
			
		||||
void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,6 +229,7 @@ uint8_t tls_parse_client_hello(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suit
 | 
			
		|||
                    case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
 | 
			
		||||
                        thep->client_knows_standard_ecc_ciphersuite = true;
 | 
			
		||||
                    /* no break */
 | 
			
		||||
                    /* fall through */
 | 
			
		||||
                    case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_COMPAT:
 | 
			
		||||
                        tr_debug("Client Sup ECC");
 | 
			
		||||
                        ret_val |= SEC_CIPHERSUITE_ECC;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,16 +53,24 @@ typedef enum {
 | 
			
		|||
    EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED
 | 
			
		||||
} eap_tls_sec_prot_state_e;
 | 
			
		||||
 | 
			
		||||
// Filters initial EAPOL-key re-transmission bursts
 | 
			
		||||
#define BURST_FILTER_TIMER_TIMEOUT                  5 * 10
 | 
			
		||||
 | 
			
		||||
// How many times initial EAPOL-key is accepted on wait for identity response state
 | 
			
		||||
#define INITIAL_EAPOL_KEY_MAX_COUNT                 2
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    sec_prot_common_t             common;           /**< Common data */
 | 
			
		||||
    sec_prot_t                    *tls_prot;        /**< TLS security protocol */
 | 
			
		||||
    eapol_pdu_t                   recv_eapol_pdu;   /**< Received EAPOL PDU */
 | 
			
		||||
    tls_data_t                    tls_send;         /**< EAP-TLS send buffer */
 | 
			
		||||
    tls_data_t                    tls_recv;         /**< EAP-TLS receive buffer */
 | 
			
		||||
    uint16_t                      burst_filt_timer; /**< Burst filter timer */
 | 
			
		||||
    uint8_t                       eap_id_seq;       /**< EAP sequence */
 | 
			
		||||
    uint8_t                       recv_eap_id_seq;  /**< Last received EAP sequence */
 | 
			
		||||
    uint8_t                       eap_code;         /**< Received EAP code */
 | 
			
		||||
    uint8_t                       eap_type;         /**< Received EAP type */
 | 
			
		||||
    uint8_t                       init_key_cnt;     /**< How many time initial EAPOL-key has been received */
 | 
			
		||||
    int8_t                        tls_result;       /**< Result of TLS operation */
 | 
			
		||||
    bool                          wait_tls: 1;      /**< Wait TLS (ECC calculation) before sending EAP-TLS message */
 | 
			
		||||
    bool                          tls_ongoing: 1;   /**< TLS handshake is ongoing */
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +159,7 @@ static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot)
 | 
			
		|||
    sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT);
 | 
			
		||||
 | 
			
		||||
    data->tls_prot = NULL;
 | 
			
		||||
    data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
 | 
			
		||||
    data->eap_id_seq = 0;
 | 
			
		||||
    data->recv_eap_id_seq = 0;
 | 
			
		||||
    data->eap_code = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -158,6 +167,7 @@ static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot)
 | 
			
		|||
    eap_tls_sec_prot_lib_message_init(&data->tls_recv);
 | 
			
		||||
    eap_tls_sec_prot_lib_message_init(&data->tls_send);
 | 
			
		||||
    data->tls_result = EAP_TLS_RESULT_ERROR;
 | 
			
		||||
    data->init_key_cnt = 0;
 | 
			
		||||
    data->wait_tls = false;
 | 
			
		||||
    data->tls_ongoing = false;
 | 
			
		||||
    data->send_pending = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -186,13 +196,31 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_
 | 
			
		|||
 | 
			
		||||
    // Decoding is successful
 | 
			
		||||
    if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
 | 
			
		||||
        // Handle only EAP messages (ignore initial EAPOL-key retransmissions)
 | 
			
		||||
        // Handle EAP messages
 | 
			
		||||
        if (data->recv_eapol_pdu.packet_type == EAPOL_EAP_TYPE) {
 | 
			
		||||
            data->eap_code = data->recv_eapol_pdu.msg.eap.eap_code;
 | 
			
		||||
            data->eap_type = data->recv_eapol_pdu.msg.eap.type;
 | 
			
		||||
 | 
			
		||||
            // Call state machine
 | 
			
		||||
            prot->state_machine(prot);
 | 
			
		||||
        } else if (data->recv_eapol_pdu.packet_type == EAPOL_KEY_TYPE &&
 | 
			
		||||
                   sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_ID) {
 | 
			
		||||
            /* If initial EAPOL-key transmission arrives to first EAP-TLS wait state i.e.
 | 
			
		||||
             * when waiting for identity response, triggers re-transmission of identity
 | 
			
		||||
             * request. This allows the supplicant to start EAP-TLS right away, if it has
 | 
			
		||||
             * missed the original identity request.
 | 
			
		||||
             */
 | 
			
		||||
            if (data->burst_filt_timer == 0 && data->init_key_cnt < INITIAL_EAPOL_KEY_MAX_COUNT) {
 | 
			
		||||
                tr_info("EAP-TLS: initial EAPOL-key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
 | 
			
		||||
                sec_prot_result_set(&data->common, SEC_RESULT_TIMEOUT);
 | 
			
		||||
                // Call state machine
 | 
			
		||||
                prot->state_machine(prot);
 | 
			
		||||
                // Resets trickle timer to give time for supplicant to answer
 | 
			
		||||
                sec_prot_timer_trickle_start(&data->common, &eap_tls_trickle_params);
 | 
			
		||||
                data->init_key_cnt++;
 | 
			
		||||
            }
 | 
			
		||||
            // Filters repeated initial EAPOL-key messages
 | 
			
		||||
            data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
 | 
			
		||||
        }
 | 
			
		||||
        ret_val = 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -288,6 +316,13 @@ static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
 | 
			
		|||
static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
 | 
			
		||||
{
 | 
			
		||||
    eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
 | 
			
		||||
 | 
			
		||||
    if (data->burst_filt_timer > ticks) {
 | 
			
		||||
        data->burst_filt_timer -= ticks;
 | 
			
		||||
    } else {
 | 
			
		||||
        data->burst_filt_timer = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,10 +72,10 @@ typedef struct {
 | 
			
		|||
    bool                          send_pending: 1;  /**< TLS data is not yet send to network */
 | 
			
		||||
} eap_tls_sec_prot_int_t;
 | 
			
		||||
 | 
			
		||||
#define FWH_RETRY_TIMEOUT_SMALL 330*10 // retry timeout for small network additional 30 seconds for authenticator delay
 | 
			
		||||
#define FWH_RETRY_TIMEOUT_LARGE 750*10 // retry timeout for large network additional 30 seconds for authenticator delay
 | 
			
		||||
#define EAP_TLS_RETRY_TIMEOUT_SMALL 330*10 // retry timeout for small network additional 30 seconds for authenticator delay
 | 
			
		||||
#define EAP_TLS_RETRY_TIMEOUT_LARGE 750*10 // retry timeout for large network additional 30 seconds for authenticator delay
 | 
			
		||||
 | 
			
		||||
static uint16_t retry_timeout = FWH_RETRY_TIMEOUT_SMALL;
 | 
			
		||||
static uint16_t retry_timeout = EAP_TLS_RETRY_TIMEOUT_SMALL;
 | 
			
		||||
 | 
			
		||||
static uint16_t supp_eap_tls_sec_prot_size(void);
 | 
			
		||||
static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot);
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks
 | 
			
		|||
static int8_t supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot);
 | 
			
		||||
static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot);
 | 
			
		||||
 | 
			
		||||
static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot);
 | 
			
		||||
static bool supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot);
 | 
			
		||||
 | 
			
		||||
#define eap_tls_sec_prot_get(prot) (eap_tls_sec_prot_int_t *) &prot->data
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -113,9 +113,9 @@ int8_t supp_eap_tls_sec_prot_register(kmp_service_t *service)
 | 
			
		|||
int8_t supp_eap_sec_prot_timing_adjust(uint8_t timing)
 | 
			
		||||
{
 | 
			
		||||
    if (timing < 16) {
 | 
			
		||||
        retry_timeout = FWH_RETRY_TIMEOUT_SMALL;
 | 
			
		||||
        retry_timeout = EAP_TLS_RETRY_TIMEOUT_SMALL;
 | 
			
		||||
    } else {
 | 
			
		||||
        retry_timeout = FWH_RETRY_TIMEOUT_LARGE;
 | 
			
		||||
        retry_timeout = EAP_TLS_RETRY_TIMEOUT_LARGE;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -493,7 +493,10 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
 | 
			
		|||
                }
 | 
			
		||||
 | 
			
		||||
                // Store sequence ID
 | 
			
		||||
                supp_eap_tls_sec_prot_seq_id_update(prot);
 | 
			
		||||
                if (supp_eap_tls_sec_prot_seq_id_update(prot)) {
 | 
			
		||||
                    // When receiving a new sequence number, adds more time for re-send if no response
 | 
			
		||||
                    data->common.ticks = retry_timeout;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // All fragments received for a message
 | 
			
		||||
                if (result == EAP_TLS_MSG_RECEIVE_DONE && data->tls_ongoing) {
 | 
			
		||||
| 
						 | 
				
			
			@ -524,10 +527,6 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
 | 
			
		|||
            // Send EAP response
 | 
			
		||||
            supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING);
 | 
			
		||||
            data->send_pending = false;
 | 
			
		||||
 | 
			
		||||
            // Add more time for re-send if no response
 | 
			
		||||
            data->common.ticks = retry_timeout;
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case EAP_TLS_STATE_FINISH:
 | 
			
		||||
| 
						 | 
				
			
			@ -550,10 +549,16 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot)
 | 
			
		||||
static bool supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot)
 | 
			
		||||
{
 | 
			
		||||
    eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
 | 
			
		||||
    bool new_seq_id = false;
 | 
			
		||||
 | 
			
		||||
    if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) {
 | 
			
		||||
        new_seq_id = true;
 | 
			
		||||
    }
 | 
			
		||||
    data->eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq;
 | 
			
		||||
    return new_seq_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* HAVE_WS */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -414,7 +414,8 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
 | 
			
		|||
                if (auth_fwh_sec_prot_mic_validate(prot) < 0) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // PTK is fresh for installing any GTKs
 | 
			
		||||
                sec_prot_keys_ptk_installed_gtk_hash_clear_all(prot->sec_keys);
 | 
			
		||||
                // If GTK was inserted set it valid
 | 
			
		||||
                sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
 | 
			
		||||
                // Reset PTK mismatch
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -315,6 +315,9 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
 | 
			
		|||
            sec_prot_timer_trickle_start(&data->common, &gkh_trickle_params);
 | 
			
		||||
 | 
			
		||||
            sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2);
 | 
			
		||||
 | 
			
		||||
            // Store the hash for to-be installed GTK as used for the PTK
 | 
			
		||||
            sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        // Wait GKH message 2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -318,10 +318,10 @@ static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e
 | 
			
		|||
 | 
			
		||||
    // Indicates TX failure
 | 
			
		||||
    if (tx_status == SEC_PROT_TX_ERR_TX_NO_ACK) {
 | 
			
		||||
        sec_prot_result_set(&data->common, KMP_RESULT_ERR_TX_NO_ACK);
 | 
			
		||||
        sec_prot_result_set(&data->common, SEC_RESULT_ERR_TX_NO_ACK);
 | 
			
		||||
    } else if (tx_status != SEC_PROT_TX_OK) {
 | 
			
		||||
        // Indicates other failure
 | 
			
		||||
        sec_prot_result_set(&data->common, KMP_RESULT_ERR_UNSPEC);
 | 
			
		||||
        sec_prot_result_set(&data->common, SEC_RESULT_ERR_UNSPEC);
 | 
			
		||||
    }
 | 
			
		||||
    prot->state_machine_call(prot);
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,8 @@
 | 
			
		|||
 | 
			
		||||
#define TRACE_GROUP "spke"
 | 
			
		||||
 | 
			
		||||
static const uint8_t empty_hash[GTK_HASH_LEN] = {0};
 | 
			
		||||
 | 
			
		||||
sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs)
 | 
			
		||||
{
 | 
			
		||||
    sec_prot_keys_t *sec_keys = ns_dyn_mem_alloc(sizeof(sec_prot_keys_t));
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +69,7 @@ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, co
 | 
			
		|||
    sec_keys->ptk_eui_64_set = false;
 | 
			
		||||
    sec_keys->pmk_mismatch = false;
 | 
			
		||||
    sec_keys->ptk_mismatch = false;
 | 
			
		||||
    sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_keys);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sec_prot_keys_delete(sec_prot_keys_t *sec_keys)
 | 
			
		||||
| 
						 | 
				
			
			@ -581,9 +584,22 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhas
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash)
 | 
			
		||||
int8_t sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash)
 | 
			
		||||
{
 | 
			
		||||
    return sec_prot_lib_gtkhash_generate(gtk, gtk_hash);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t gtk_hash[8];
 | 
			
		||||
    sec_prot_lib_gtkhash_generate(gtk, gtk_hash);
 | 
			
		||||
 | 
			
		||||
    // Checks if GTK hash for the GTK would be all zero
 | 
			
		||||
    if (memcmp(gtk_hash, empty_hash, GTK_HASH_LEN) == 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash)
 | 
			
		||||
| 
						 | 
				
			
			@ -639,7 +655,6 @@ gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t
 | 
			
		|||
 | 
			
		||||
bool sec_prot_keys_gtk_hash_empty(uint8_t *gtkhash)
 | 
			
		||||
{
 | 
			
		||||
    const uint8_t empty_hash[GTK_HASH_LEN] = {0};
 | 
			
		||||
    if (memcmp(gtkhash, empty_hash, GTK_HASH_LEN) == 0) {
 | 
			
		||||
        return true;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -783,4 +798,57 @@ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks)
 | 
			
		|||
    return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys)
 | 
			
		||||
{
 | 
			
		||||
    for (uint8_t index = 0; index < GTK_NUM; index++) {
 | 
			
		||||
        memset(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, 0, INS_GTK_HASH_LEN);
 | 
			
		||||
    }
 | 
			
		||||
    sec_keys->ins_gtk_hash_set = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys)
 | 
			
		||||
{
 | 
			
		||||
    if (sec_keys->gtk_set_index >= 0) {
 | 
			
		||||
        uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, sec_keys->gtk_set_index);
 | 
			
		||||
        if (!gtk) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        uint8_t gtk_hash[GTK_HASH_LEN];
 | 
			
		||||
        if (sec_prot_keys_gtk_hash_generate(gtk, gtk_hash) < 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        /* Store two byte hash. This is long enough for the GTK installed check, since
 | 
			
		||||
         * possible conflict between hashes causes only that 4WH is initiated/is not
 | 
			
		||||
         * initiated instead of GKH.
 | 
			
		||||
         */
 | 
			
		||||
        memcpy(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN);
 | 
			
		||||
        sec_keys->ins_gtk_hash_set |= (1 << sec_keys->gtk_set_index);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index)
 | 
			
		||||
{
 | 
			
		||||
    if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, gtk_index);
 | 
			
		||||
    if (!gtk) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Calculated GTK hash for the current GTK on the defined index
 | 
			
		||||
    uint8_t gtk_hash[GTK_HASH_LEN];
 | 
			
		||||
    if (sec_prot_keys_gtk_hash_generate(gtk, gtk_hash) < 0) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If PTK has been used to install different GTK to index than the current one, trigger mismatch
 | 
			
		||||
    if (memcmp(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN) != 0) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* HAVE_WS */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,7 @@
 | 
			
		|||
 | 
			
		||||
#define GTK_HASH_LEN              8
 | 
			
		||||
#define GTK_ALL_HASHES_LEN        GTK_HASH_LEN * GTK_NUM
 | 
			
		||||
#define INS_GTK_HASH_LEN          2
 | 
			
		||||
 | 
			
		||||
#define PMK_LIFETIME_INSTALL      0xFFFFF
 | 
			
		||||
#define PTK_LIFETIME_INSTALL      0xFFFFF
 | 
			
		||||
| 
						 | 
				
			
			@ -71,18 +72,24 @@ typedef struct {
 | 
			
		|||
    bool                   updated: 1;                /**< Group Transient Keys has been updated */
 | 
			
		||||
} sec_prot_gtk_keys_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint8_t                hash[INS_GTK_HASH_LEN];    /**< Inserted GTKs for a PTK hash */
 | 
			
		||||
} sec_prot_gtk_hash_t;
 | 
			
		||||
 | 
			
		||||
// Security key data
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint64_t               pmk_key_replay_cnt;        /**< Pairwise Master Key replay counter */
 | 
			
		||||
    uint8_t                pmk[PMK_LEN];              /**< Pairwise Master Key (256 bits) */
 | 
			
		||||
    uint8_t                ptk[PTK_LEN];              /**< Pairwise Transient Key (384 bits) */
 | 
			
		||||
    uint8_t                ptk_eui_64[8];             /**< Remote EUI-64 used to derive PTK or NULL */
 | 
			
		||||
    sec_prot_gtk_hash_t    ins_gtk_hash[GTK_NUM];     /**< Hashes for inserted GTKs for a PTK */
 | 
			
		||||
    sec_prot_gtk_keys_t    *gtks;                     /**< Group Transient Keys */
 | 
			
		||||
    const sec_prot_certs_t *certs;                    /**< Certificates */
 | 
			
		||||
    uint32_t               pmk_lifetime;              /**< PMK lifetime in seconds */
 | 
			
		||||
    uint32_t               ptk_lifetime;              /**< PTK lifetime in seconds */
 | 
			
		||||
    uint8_t                gtkl;                      /**< Remote GTKL information */
 | 
			
		||||
    int8_t                 gtk_set_index;             /**< Index of GTK to set */
 | 
			
		||||
    unsigned               ins_gtk_hash_set: 4;       /**< Hash for inserted GTKs for a PTK set */
 | 
			
		||||
    bool                   pmk_set: 1;                /**< Pairwise Master Key set */
 | 
			
		||||
    bool                   ptk_set: 1;                /**< Pairwise Transient Key set */
 | 
			
		||||
    bool                   pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +102,8 @@ typedef struct {
 | 
			
		|||
// Frame counter data
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint8_t gtk[GTK_LEN];                             /**< GTK of the frame counter */
 | 
			
		||||
    uint32_t frame_counter;                           /**< Frame counter */
 | 
			
		||||
    uint32_t frame_counter;                           /**< Current frame counter */
 | 
			
		||||
    uint32_t stored_frame_counter;                    /**< Stored Frame counter */
 | 
			
		||||
    bool set : 1;                                     /**< Value has been set */
 | 
			
		||||
} frame_counter_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -649,8 +657,20 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtk_ha
 | 
			
		|||
 * \param gtk GTK key
 | 
			
		||||
 * \param gtk_hash GTK hash for a GTK
 | 
			
		||||
 *
 | 
			
		||||
 * \return < 0 failure
 | 
			
		||||
 * \return >= 0 success
 | 
			
		||||
 */
 | 
			
		||||
void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash);
 | 
			
		||||
int8_t sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sec_prot_keys_gtk_valid_check check if GTK is valid
 | 
			
		||||
 *
 | 
			
		||||
 * \param gtk GTK key
 | 
			
		||||
 *
 | 
			
		||||
 * \return < 0 failure
 | 
			
		||||
 * \return >= 0 success
 | 
			
		||||
 */
 | 
			
		||||
int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sec_prot_keys_gtks_hash_update update GTKs based on GTK hash
 | 
			
		||||
| 
						 | 
				
			
			@ -751,4 +771,30 @@ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks);
 | 
			
		|||
 */
 | 
			
		||||
uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sec_prot_keys_ptk_installed_gtk_hash_clear_all clear GTK hashes of the GTKs that has been installed
 | 
			
		||||
 *                                                to supplicant using the PTK
 | 
			
		||||
 * \param sec_keys security keys
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sec_prot_keys_ptk_installed_gtk_hash_set set GTK hash of the GTK that has been installed
 | 
			
		||||
 *                                          to supplicant using the current PTK
 | 
			
		||||
 *
 | 
			
		||||
 * \param sec_keys security keys
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sec_prot_keys_ptk_installed_gtk_hash_set check if PTK is being used to store new GTK for the index
 | 
			
		||||
 *                                          for the supplicant i.e. GTK hash would change
 | 
			
		||||
 *
 | 
			
		||||
 * \param sec_keys security keys
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index);
 | 
			
		||||
 | 
			
		||||
#endif /* SEC_PROT_KEYS_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,6 +49,26 @@ void trickle_start(trickle_t *t, const trickle_params_t *params)
 | 
			
		|||
    trickle_begin_interval(t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t trickle_timer_max(const trickle_params_t *params, uint8_t trickle_timer_expiration)
 | 
			
		||||
{
 | 
			
		||||
    trickle_time_t time_I = params->Imin - 1;
 | 
			
		||||
    uint32_t total_time = time_I;
 | 
			
		||||
    while (trickle_timer_expiration) {
 | 
			
		||||
        if (time_I <= TRICKLE_TIME_MAX / 2) {
 | 
			
		||||
            time_I *= 2;
 | 
			
		||||
        } else {
 | 
			
		||||
            time_I = TRICKLE_TIME_MAX;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (time_I > params->Imax) {
 | 
			
		||||
            time_I = params->Imax;
 | 
			
		||||
        }
 | 
			
		||||
        total_time += time_I;
 | 
			
		||||
        trickle_timer_expiration--;
 | 
			
		||||
    }
 | 
			
		||||
    return total_time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* We don't expose the raw reset as API; users should use "inconsistent_heard".
 | 
			
		||||
 * This avoids repeated resets stopping transmission by restarting the interval.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,5 +76,10 @@ bool trickle_running(const trickle_t *t, const trickle_params_t *params);
 | 
			
		|||
 | 
			
		||||
/* Stop the timer (by setting e to infinite) */
 | 
			
		||||
void trickle_stop(trickle_t *t);
 | 
			
		||||
/*
 | 
			
		||||
 * Call return max time after n count expiration period 0 return 1 Imin - 1 period
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
uint32_t trickle_timer_max(const trickle_params_t *params, uint8_t trickle_timer_expiration);
 | 
			
		||||
 | 
			
		||||
#endif /* TRICKLE_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,7 +87,7 @@ bool blacklist_reject(const uint8_t *ll64_address)
 | 
			
		|||
    if (blacklist_entry) {
 | 
			
		||||
        // If address is blacklisted rejects
 | 
			
		||||
        if (blacklist_entry->ttl > blacklist_data->blacklist_entry_lifetime) {
 | 
			
		||||
            tr_debug("blacklist reject: %s", trace_array(ll64_address + 8, 8));
 | 
			
		||||
            tr_info("blacklist reject: %s", trace_array(ll64_address + 8, 8));
 | 
			
		||||
            return true;
 | 
			
		||||
            // Neighbor heard; updates blacklist entry TTL to full lifetime
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ void blacklist_update(const uint8_t *ll64_address, bool success)
 | 
			
		|||
    // On successful link establishment remove address from blacklist
 | 
			
		||||
    if (success) {
 | 
			
		||||
        if (blacklist_entry) {
 | 
			
		||||
            tr_debug("Blacklist removed");
 | 
			
		||||
            tr_info("Blacklist removed");
 | 
			
		||||
            blacklist_entry_free(blacklist_entry);
 | 
			
		||||
        }
 | 
			
		||||
        // On failure add address to blacklist or update timeout
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +144,7 @@ void blacklist_update(const uint8_t *ll64_address, bool success)
 | 
			
		|||
            /* TTL is blacklist entry lifetime + from 1.0 to 1.5 * interval */
 | 
			
		||||
            blacklist_entry->ttl = blacklist_data->blacklist_entry_lifetime + randLIB_randomise_base(blacklist_entry->interval, 0x8000, 0xC000);
 | 
			
		||||
        } else {
 | 
			
		||||
            tr_debug("Blacklist add");
 | 
			
		||||
            tr_info("Blacklist add");
 | 
			
		||||
            blacklist_entry_add(ll64_address + 8);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +209,7 @@ void blacklist_ttl_update(uint16_t ticks)
 | 
			
		|||
        if (blacklist_entry->ttl > ticks) {
 | 
			
		||||
            blacklist_entry->ttl -= ticks;
 | 
			
		||||
        } else {
 | 
			
		||||
            tr_debug("Blacklist remove entry: %s", trace_array(blacklist_entry->eui64, 8));
 | 
			
		||||
            tr_info("Blacklist remove entry: %s", trace_array(blacklist_entry->eui64, 8));
 | 
			
		||||
            blacklist_entry_free(blacklist_entry);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,11 +62,13 @@ typedef struct {
 | 
			
		|||
    etx_storage_t *etx_storage_list;
 | 
			
		||||
    etx_sample_storage_t *etx_cache_storage_list;
 | 
			
		||||
    uint32_t max_etx_update;
 | 
			
		||||
    uint32_t max_etx;
 | 
			
		||||
    uint16_t hysteresis;                            // 12 bit fraction
 | 
			
		||||
    uint16_t init_etx_sample_count;
 | 
			
		||||
    uint8_t accum_threshold;
 | 
			
		||||
    uint8_t etx_min_sampling_time;
 | 
			
		||||
    uint8_t ext_storage_list_size;
 | 
			
		||||
    uint8_t min_sample_count;
 | 
			
		||||
    uint8_t min_attempts_count;
 | 
			
		||||
    bool cache_sample_requested;
 | 
			
		||||
    int8_t interface_id;
 | 
			
		||||
} ext_info_t;
 | 
			
		||||
| 
						 | 
				
			
			@ -79,8 +81,10 @@ static ext_info_t etx_info = {
 | 
			
		|||
    .etx_storage_list = NULL,
 | 
			
		||||
    .etx_cache_storage_list = NULL,
 | 
			
		||||
    .ext_storage_list_size = 0,
 | 
			
		||||
    .min_sample_count = 0,
 | 
			
		||||
    .min_attempts_count = 0,
 | 
			
		||||
    .max_etx_update = 0,
 | 
			
		||||
    .max_etx = 0xffff,
 | 
			
		||||
    .init_etx_sample_count = 1,
 | 
			
		||||
    .cache_sample_requested = false,
 | 
			
		||||
    .etx_min_sampling_time = 0,
 | 
			
		||||
    .interface_id = -1
 | 
			
		||||
| 
						 | 
				
			
			@ -89,8 +93,10 @@ static ext_info_t etx_info = {
 | 
			
		|||
static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index)
 | 
			
		||||
{
 | 
			
		||||
    if (etx_info.hysteresis && !entry->stored_diff_etx) {
 | 
			
		||||
        if (entry->etx_samples >= etx_info.init_etx_sample_count) {
 | 
			
		||||
            entry->stored_diff_etx = entry->etx;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t etx = attempts << (12 - ETX_MOVING_AVERAGE_FRACTION);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,11 +105,14 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack
 | 
			
		|||
    } else  {
 | 
			
		||||
        etx = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((etx_info.max_etx_update) && etx > etx_info.max_etx_update) {
 | 
			
		||||
        etx = etx_info.max_etx_update;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (etx_info.cache_sample_requested && entry->etx_samples == 1) {
 | 
			
		||||
    //tr_debug("Attempts %u ACK %u 1/8 update %u", attempts, acks_rx, etx);
 | 
			
		||||
 | 
			
		||||
    if (etx_info.cache_sample_requested && entry->etx_samples <= etx_info.init_etx_sample_count) {
 | 
			
		||||
        // skip the initial value as RSSI generated ETX is not valid
 | 
			
		||||
        etx = etx << 3;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -111,18 +120,20 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack
 | 
			
		|||
        etx += entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (etx > 0xffff) {
 | 
			
		||||
        etx = 0xffff;
 | 
			
		||||
    if (etx > etx_info.max_etx) {
 | 
			
		||||
        etx = etx_info.max_etx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If real ETX value has been received do not update based on LQI or dBm
 | 
			
		||||
    entry->tmp_etx = false;
 | 
			
		||||
 | 
			
		||||
    entry->etx = etx;
 | 
			
		||||
 | 
			
		||||
    if (entry->etx_samples >= etx_info.init_etx_sample_count) {
 | 
			
		||||
        etx_cache_entry_init(attribute_index);
 | 
			
		||||
 | 
			
		||||
        // Checks if ETX value change callback is needed
 | 
			
		||||
        etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void etx_cache_entry_init(uint8_t attribute_index)
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +146,6 @@ static void etx_cache_entry_init(uint8_t attribute_index)
 | 
			
		|||
    storage->attempts_count = 0;
 | 
			
		||||
    storage->etx_timer = etx_info.etx_min_sampling_time;
 | 
			
		||||
    storage->received_acks = 0;
 | 
			
		||||
    storage->sample_count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *entry, uint16_t time_update)
 | 
			
		||||
| 
						 | 
				
			
			@ -148,23 +158,23 @@ static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *en
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (entry->etx_samples > ETX_ACCELERATED_SAMPLE_COUNT) {
 | 
			
		||||
    if (entry->etx_samples > etx_info.init_etx_sample_count) {
 | 
			
		||||
        //Slower ETX update phase
 | 
			
		||||
        if (storage->sample_count < etx_info.min_sample_count || storage->etx_timer) {
 | 
			
		||||
            if (storage->sample_count < 0xff) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        //Accelerated ETX at for new neighbor
 | 
			
		||||
        if (storage->sample_count < ETX_ACCELERATED_INTERVAL) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks);
 | 
			
		||||
        if (storage->attempts_count >= etx_info.min_attempts_count) {
 | 
			
		||||
 | 
			
		||||
            if (storage->etx_timer == 0 || storage->attempts_count == 0xffff || storage->received_acks == 0xff) {
 | 
			
		||||
                //Got least min sample in requested time or max possible sample
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (time_update == 0) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +186,6 @@ static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, ui
 | 
			
		|||
    if (ack_rx) {
 | 
			
		||||
        storage->received_acks++;
 | 
			
		||||
    }
 | 
			
		||||
    storage->sample_count++;
 | 
			
		||||
    return storage;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +211,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
 | 
			
		|||
    if (!entry) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (entry->etx_samples < 7) {
 | 
			
		||||
        entry->etx_samples++;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -211,11 +221,15 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
 | 
			
		|||
        etx_sample_storage_t *storage = etx_cache_sample_update(attribute_index, attempts, success);
 | 
			
		||||
        entry->accumulated_failures = 0;
 | 
			
		||||
 | 
			
		||||
        if (!entry->etx || (entry->etx_samples > 1 &&  !etx_update_possible(storage, entry, 0))) {
 | 
			
		||||
        if (!etx_update_possible(storage, entry, 0)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index);
 | 
			
		||||
 | 
			
		||||
        if (entry->etx_samples < 7 && !success) {
 | 
			
		||||
            entry->etx_samples = 7; //Stop Probing to failure
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -377,6 +391,13 @@ uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index)
 | 
			
		|||
    if (!entry) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (etx_info.cache_sample_requested && entry->etx_samples < etx_info.init_etx_sample_count) {
 | 
			
		||||
        if (!entry->etx_samples) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return etx_current_calc(entry->etx, entry->accumulated_failures) >> 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +454,12 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
 | 
			
		|||
        if (!entry->etx) {
 | 
			
		||||
            etx = etx_dbm_lqi_calc(lqi, dbm);
 | 
			
		||||
            entry->etx = etx;
 | 
			
		||||
            entry->stored_diff_etx = etx;
 | 
			
		||||
            entry->tmp_etx = true;
 | 
			
		||||
            if (etx_info.callback_ptr) {
 | 
			
		||||
                etx_info.callback_ptr(etx_info.interface_id, 0, entry->etx >> 4,
 | 
			
		||||
                                      attribute_index);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // If local ETX has been calculated without remote incoming IDR and
 | 
			
		||||
        // remote incoming IDR is available update it by remote incoming IDR value
 | 
			
		||||
| 
						 | 
				
			
			@ -448,11 +474,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
 | 
			
		|||
            entry->etx = etx >> 12;
 | 
			
		||||
 | 
			
		||||
            local_incoming_idr >>= 4;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If local ETX has been calculated indicates new neighbor
 | 
			
		||||
        if (etx) {
 | 
			
		||||
            etx_neighbor_add(interface_id, attribute_index);
 | 
			
		||||
            etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -585,14 +607,18 @@ bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size)
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count)
 | 
			
		||||
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_attempts_count, uint8_t init_etx_sample_count)
 | 
			
		||||
{
 | 
			
		||||
    //No ini ETX allocation done yet
 | 
			
		||||
    if (etx_info.ext_storage_list_size == 0) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (min_wait_time || etx_min_sample_count) {
 | 
			
		||||
    if (min_wait_time || etx_min_attempts_count) {
 | 
			
		||||
        if (init_etx_sample_count == 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!etx_info.etx_cache_storage_list) {
 | 
			
		||||
            //allocate
 | 
			
		||||
            etx_info.etx_cache_storage_list = ns_dyn_mem_alloc(sizeof(etx_sample_storage_t) * etx_info.ext_storage_list_size);
 | 
			
		||||
| 
						 | 
				
			
			@ -615,8 +641,9 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_
 | 
			
		|||
        etx_info.etx_cache_storage_list = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    etx_info.min_sample_count = etx_min_sample_count;
 | 
			
		||||
    etx_info.min_attempts_count = etx_min_attempts_count;
 | 
			
		||||
    etx_info.etx_min_sampling_time = min_wait_time;
 | 
			
		||||
    etx_info.init_etx_sample_count = init_etx_sample_count;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -624,12 +651,23 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_
 | 
			
		|||
void etx_max_update_set(uint16_t etx_max_update)
 | 
			
		||||
{
 | 
			
		||||
    if (etx_max_update) {
 | 
			
		||||
        //Define MAX ETX UPDATE
 | 
			
		||||
        etx_info.max_etx_update = (etx_max_update / 128) << (12 - ETX_MOVING_AVERAGE_FRACTION);
 | 
			
		||||
    } else {
 | 
			
		||||
        etx_info.max_etx_update = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void etx_max_set(uint16_t etx_max)
 | 
			
		||||
{
 | 
			
		||||
    if (etx_max) {
 | 
			
		||||
        //Define MAX ETX possible value
 | 
			
		||||
        etx_info.max_etx = (etx_max / 128) << 12;
 | 
			
		||||
    } else {
 | 
			
		||||
        etx_info.max_etx = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
etx_storage_t *etx_storage_entry_get(int8_t interface_id, uint8_t attribute_index)
 | 
			
		||||
{
 | 
			
		||||
    if (etx_info.interface_id != interface_id || !etx_info.etx_storage_list || attribute_index >= etx_info.ext_storage_list_size) {
 | 
			
		||||
| 
						 | 
				
			
			@ -698,6 +736,8 @@ static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *store
 | 
			
		|||
    if (current_etx > *stored_diff_etx) {
 | 
			
		||||
        if (current_etx - *stored_diff_etx >= etx_info.hysteresis) {
 | 
			
		||||
            callback = true;
 | 
			
		||||
        } else if (current_etx == etx_info.max_etx && *stored_diff_etx != etx_info.max_etx) {
 | 
			
		||||
            callback = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (current_etx < *stored_diff_etx) {
 | 
			
		||||
        if (*stored_diff_etx - current_etx >= etx_info.hysteresis) {
 | 
			
		||||
| 
						 | 
				
			
			@ -768,35 +808,6 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief A function to add ETX neighbor
 | 
			
		||||
 *
 | 
			
		||||
 *  Notifies ETX module that neighbor has been added. Calls ETX value change callback
 | 
			
		||||
 *  if that is set.
 | 
			
		||||
 *
 | 
			
		||||
 * \param mac64_addr_ptr long MAC address
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    //tr_debug("Add attribute %u", attribute_index);
 | 
			
		||||
    uint16_t stored_diff_etx;
 | 
			
		||||
    etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index);
 | 
			
		||||
    if (entry && etx_info.callback_ptr) {
 | 
			
		||||
        // Gets table entry
 | 
			
		||||
 | 
			
		||||
        if (entry->etx) {
 | 
			
		||||
            stored_diff_etx = entry->stored_diff_etx;
 | 
			
		||||
            if (!stored_diff_etx) {
 | 
			
		||||
                stored_diff_etx = entry->etx;
 | 
			
		||||
            }
 | 
			
		||||
            etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx >> 4, entry->etx >> 4,
 | 
			
		||||
                                  attribute_index);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void etx_cache_timer(int8_t interface_id, uint16_t seconds_update)
 | 
			
		||||
{
 | 
			
		||||
    if (!etx_info.cache_sample_requested) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,6 @@ typedef struct etx_sample_storage_s {
 | 
			
		|||
    uint16_t           attempts_count;         /*!< TX attempt count */
 | 
			
		||||
    uint8_t            etx_timer;              /*!< Count down from configured value 0 means that ETX Update is possible done again*/
 | 
			
		||||
    uint8_t            received_acks;          /*!< Received ACK's */
 | 
			
		||||
    uint8_t            sample_count;           /*!< Finished TX count */
 | 
			
		||||
} etx_sample_storage_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -237,17 +236,6 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int
 | 
			
		|||
 */
 | 
			
		||||
void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief A function to add ETX neighbor
 | 
			
		||||
 *
 | 
			
		||||
 *  Notifies ETX module that neighbor has been added. Calls ETX value change callback
 | 
			
		||||
 *  if that is set.
 | 
			
		||||
 *
 | 
			
		||||
 * \param attribute_index Neighbour attribute index
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief A function for update cached ETX calculation
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -266,13 +254,14 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update);
 | 
			
		|||
 *  ETX update will happen when min wait time is reached and also reached min etx sample count.
 | 
			
		||||
 *
 | 
			
		||||
 * \param min_wait_time how many seconds must wait before do new ETX
 | 
			
		||||
 * \param etx_min_sample_count define how many completed TX process must be done for new ETX. Min accepted value is 4.
 | 
			
		||||
 * \param etx_min_attempts_count define how many TX attempts process must be done for new ETX. Min accepted value is 4.
 | 
			
		||||
 * \param init_etx_sample_count How Many sample is need to init etx calculate
 | 
			
		||||
 *
 | 
			
		||||
 * \return true Enable is OK
 | 
			
		||||
 * \return false Memory allocation fail
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count);
 | 
			
		||||
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_attempts_count, uint8_t init_etx_sample_count);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -285,4 +274,14 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_
 | 
			
		|||
 */
 | 
			
		||||
void etx_max_update_set(uint16_t etx_max_update);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief A function for set Maxium ETX value
 | 
			
		||||
 *
 | 
			
		||||
 * ETX RFC define that that Max value is 0xffff but this API cuold make that Poor link start go down slowly.
 | 
			
		||||
 *
 | 
			
		||||
 * \param etx_max 0 No limit for higher value means. This pameter will change normal ETX which could be 0xffff.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void etx_max_set(uint16_t etx_max);
 | 
			
		||||
 | 
			
		||||
#endif /* ETX_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1123,8 +1123,9 @@ static void fhss_data_tx_done_callback(const fhss_api_t *api, bool waiting_ack,
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type)
 | 
			
		||||
static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel)
 | 
			
		||||
{
 | 
			
		||||
    (void) channel;
 | 
			
		||||
    fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
 | 
			
		||||
    if (!fhss_structure) {
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1384,7 +1385,9 @@ static void fhss_beacon_tasklet_func(arm_event_s *event)
 | 
			
		|||
    if (!fhss_structure) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef FEA_TRACE_SUPPORT
 | 
			
		||||
    uint8_t parent_address[8];
 | 
			
		||||
#endif
 | 
			
		||||
    fhss_clear_active_event(fhss_structure, event->event_type);
 | 
			
		||||
    // skip the init event as there will be a timer event after
 | 
			
		||||
    if (event->event_type == FHSS_TIMER_EVENT) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,7 +113,10 @@ int8_t fhss_disable(fhss_structure_t *fhss_structure)
 | 
			
		|||
    }
 | 
			
		||||
    fhss_structure->fhss_api->synch_state_set(fhss_structure->fhss_api, FHSS_UNSYNCHRONIZED, 0);
 | 
			
		||||
    ns_dyn_mem_free(fhss_structure->bs);
 | 
			
		||||
    ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table);
 | 
			
		||||
    ns_dyn_mem_free(fhss_structure->ws->tr51_output_table);
 | 
			
		||||
    ns_dyn_mem_free(fhss_structure->ws);
 | 
			
		||||
    fhss_failed_list_free(fhss_structure);
 | 
			
		||||
    ns_dyn_mem_free(fhss_structure);
 | 
			
		||||
    fhss_struct = 0;
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ struct fhss_structure {
 | 
			
		|||
    int8_t fhss_event_timer;
 | 
			
		||||
    uint8_t active_fhss_events;
 | 
			
		||||
    uint16_t number_of_channels;
 | 
			
		||||
    uint16_t optimal_packet_length;
 | 
			
		||||
    fhss_states fhss_state;
 | 
			
		||||
    uint32_t fhss_timeout;
 | 
			
		||||
    uint32_t fhss_timer;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 "ns_trace.h"
 | 
			
		||||
#include "fhss_api.h"
 | 
			
		||||
#include "fhss_config.h"
 | 
			
		||||
#include "fhss.h"
 | 
			
		||||
#include "fhss_common.h"
 | 
			
		||||
#include "fhss_ws.h"
 | 
			
		||||
#include "fhss_statistics.h"
 | 
			
		||||
#include "fhss_channel.h"
 | 
			
		||||
#include "channel_list.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define TRACE_GROUP "fhta"
 | 
			
		||||
 | 
			
		||||
int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length)
 | 
			
		||||
{
 | 
			
		||||
    (void) fhss_api;
 | 
			
		||||
    (void) packet_length;
 | 
			
		||||
#ifdef HAVE_WS
 | 
			
		||||
    fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api);
 | 
			
		||||
    if (!fhss_structure) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    fhss_structure->optimal_packet_length = packet_length;
 | 
			
		||||
    fhss_set_txrx_slot_length(fhss_structure);
 | 
			
		||||
    tr_debug("Setting FHSS optimal packet length to: %u", fhss_structure->optimal_packet_length);
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +83,6 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots);
 | 
			
		|||
static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure);
 | 
			
		||||
static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay);
 | 
			
		||||
static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure);
 | 
			
		||||
static uint32_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure);
 | 
			
		||||
 | 
			
		||||
// This function supports rounding up
 | 
			
		||||
static int64_t divide_integer(int64_t dividend, int32_t divisor)
 | 
			
		||||
| 
						 | 
				
			
			@ -147,10 +146,10 @@ fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configurati
 | 
			
		|||
    fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb);
 | 
			
		||||
    fhss_struct->ws->fhss_configuration = *fhss_configuration;
 | 
			
		||||
    fhss_struct->number_of_channels = channel_count;
 | 
			
		||||
    fhss_struct->optimal_packet_length = OPTIMAL_PACKET_LENGTH;
 | 
			
		||||
    fhss_ws_set_hop_count(fhss_struct, 0xff);
 | 
			
		||||
    fhss_struct->rx_channel = fhss_configuration->unicast_fixed_channel;
 | 
			
		||||
    fhss_struct->ws->min_synch_interval = DEFAULT_MIN_SYNCH_INTERVAL;
 | 
			
		||||
    fhss_set_txrx_slot_length(fhss_struct);
 | 
			
		||||
    ns_list_init(&fhss_struct->fhss_failed_tx_list);
 | 
			
		||||
    return fhss_struct;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -173,14 +172,51 @@ static int fhss_ws_manage_channel_table_allocation(fhss_structure_t *fhss_struct
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure)
 | 
			
		||||
void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / WS_MAX_TXRX_SLOT_LEN_MS) / 2;
 | 
			
		||||
    // No broadcast schedule, no TX slots
 | 
			
		||||
    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;
 | 
			
		||||
    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
 | 
			
		||||
         *
 | 
			
		||||
         * hop 0
 | 
			
		||||
         * tx'ing            |    |            | |               |   |
 | 
			
		||||
         * |   BC   |   RX   |   TX   |   RX   |   TX   |   RX   |   TX   |   BC   |
 | 
			
		||||
         * hop 1
 | 
			
		||||
         * tx'ing   |    |            | |               |   |
 | 
			
		||||
         * |   BC   |   TX   |   RX   |   TX   |   RX   |   TX   |   RX   |   BC   |
 | 
			
		||||
         * hop 2
 | 
			
		||||
         * tx'ing                 |   |             | |               |   |
 | 
			
		||||
         * |   BC   |   RX   |   TX   |   RX   |   TX   |   RX   |   TX   |   BC   |
 | 
			
		||||
         * hop 3
 | 
			
		||||
         * tx'ing        |   |             | |               |   |
 | 
			
		||||
         * |   BC   |   TX   |   RX   |   TX   |   RX   |   TX   |   RX   |   BC   |
 | 
			
		||||
         */
 | 
			
		||||
        uint32_t datarate = fhss_structure->callbacks.read_datarate(fhss_structure->fhss_api);
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / txrx_slot_length_ms_tmp) / 2;
 | 
			
		||||
    if (!number_of_tx_slots) {
 | 
			
		||||
        return 0;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    fhss_structure->ws->txrx_slot_length_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / (number_of_tx_slots * 2);
 | 
			
		||||
    return number_of_tx_slots;
 | 
			
		||||
    tr_info("TX slot length: %"PRIu32"ms", fhss_structure->ws->txrx_slot_length_ms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t fhss_get_number_of_tx_slots(fhss_structure_t *fhss_structure)
 | 
			
		||||
{
 | 
			
		||||
    return ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / fhss_structure->ws->txrx_slot_length_ms) / 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure)
 | 
			
		||||
| 
						 | 
				
			
			@ -193,8 +229,8 @@ static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure)
 | 
			
		|||
            fhss_structure->ws->bc_slot = 0;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_DH1CF) {
 | 
			
		||||
        next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
 | 
			
		||||
        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);
 | 
			
		||||
    } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_VENDOR_DEF_CF) {
 | 
			
		||||
        if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) {
 | 
			
		||||
            next_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, NULL, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
 | 
			
		||||
| 
						 | 
				
			
			@ -305,8 +341,11 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots)
 | 
			
		|||
{
 | 
			
		||||
    (void) slots;
 | 
			
		||||
    uint16_t queue_size = 0;
 | 
			
		||||
    fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id);
 | 
			
		||||
 | 
			
		||||
    fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id);
 | 
			
		||||
    if (!fhss_structure) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fhss_structure->ws->is_on_bc_channel == true) {
 | 
			
		||||
        queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -394,7 +433,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
 | 
			
		|||
    if (fhss_state == FHSS_SYNCHRONIZED) {
 | 
			
		||||
        uint32_t fhss_broadcast_interval = fhss_structure->ws->fhss_configuration.fhss_broadcast_interval;
 | 
			
		||||
        uint8_t fhss_bc_dwell_interval = fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval;
 | 
			
		||||
 | 
			
		||||
        fhss_set_txrx_slot_length(fhss_structure);
 | 
			
		||||
        // Start broadcast schedule when BC intervals are known
 | 
			
		||||
        if (fhss_broadcast_interval && fhss_bc_dwell_interval) {
 | 
			
		||||
            fhss_broadcast_handler(fhss_structure->fhss_api, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -407,6 +446,9 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
 | 
			
		|||
        }
 | 
			
		||||
    } else if (fhss_state == FHSS_UNSYNCHRONIZED) {
 | 
			
		||||
        fhss_structure->ws->synchronization_time = 0;
 | 
			
		||||
        eventOS_callback_timer_stop(fhss_structure->fhss_event_timer);
 | 
			
		||||
        fhss_stop_timer(fhss_structure, fhss_unicast_handler);
 | 
			
		||||
        fhss_stop_timer(fhss_structure, fhss_broadcast_handler);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fhss_structure->fhss_state = fhss_state;
 | 
			
		||||
| 
						 | 
				
			
			@ -531,7 +573,7 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure)
 | 
			
		|||
    if (fhss_structure->ws->is_on_bc_channel == true) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t number_of_tx_slots = fhss_set_txrx_slot_length(fhss_structure);
 | 
			
		||||
    uint32_t number_of_tx_slots = fhss_get_number_of_tx_slots(fhss_structure);
 | 
			
		||||
    // Allow transmission when broadcast interval is very short comparing to MAX slot length
 | 
			
		||||
    if (!number_of_tx_slots) {
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -539,9 +581,22 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure)
 | 
			
		|||
 | 
			
		||||
    uint32_t remaining_time_ms = get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval)) / 1000;
 | 
			
		||||
    uint32_t tx_slot_begin_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (fhss_structure->ws->txrx_slot_length_ms * (fhss_structure->own_hop & 1));
 | 
			
		||||
    /* Return false when our first TX slot has not yet started
 | 
			
		||||
     *         |------remaining_time_ms---|
 | 
			
		||||
     *         |
 | 
			
		||||
     *         v
 | 
			
		||||
     * | BC | RX | TX | RX | TX | RX | TX | BC |
 | 
			
		||||
     */
 | 
			
		||||
    if (tx_slot_begin_ms < remaining_time_ms) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    tx_slot_begin_ms = tx_slot_begin_ms - (((tx_slot_begin_ms - remaining_time_ms) / (2 * fhss_structure->ws->txrx_slot_length_ms)) * (2 * fhss_structure->ws->txrx_slot_length_ms));
 | 
			
		||||
    uint32_t rx_slot_begin_ms = tx_slot_begin_ms - fhss_structure->ws->txrx_slot_length_ms;
 | 
			
		||||
    // Check if we are currently on TX slot.
 | 
			
		||||
    /* Check if we are currently on TX slot.
 | 
			
		||||
     *              |        |        |
 | 
			
		||||
     *              v        v        v
 | 
			
		||||
     * | BC | RX | TX | RX | TX | RX | TX | BC |
 | 
			
		||||
     */
 | 
			
		||||
    if ((remaining_time_ms <= tx_slot_begin_ms) && (remaining_time_ms > rx_slot_begin_ms)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -551,6 +606,10 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure)
 | 
			
		|||
 | 
			
		||||
static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length)
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
     * Check if there is enough time for transmitting before the next multicast slot.
 | 
			
		||||
     */
 | 
			
		||||
#ifdef FHSS_WS_PROTECT_MC_SLOTS
 | 
			
		||||
    if (!fhss_structure->ws->fhss_configuration.fhss_broadcast_interval || !fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -560,6 +619,13 @@ static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
#else
 | 
			
		||||
    (void) fhss_structure;
 | 
			
		||||
    (void) tx_length;
 | 
			
		||||
    (void) phy_header_length;
 | 
			
		||||
    (void) phy_tail_length;
 | 
			
		||||
    return true;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool fhss_ws_check_tx_conditions_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t handle, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length)
 | 
			
		||||
| 
						 | 
				
			
			@ -663,7 +729,7 @@ static void fhss_ws_data_tx_done_callback(const fhss_api_t *api, bool waiting_ac
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type)
 | 
			
		||||
static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel)
 | 
			
		||||
{
 | 
			
		||||
    fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
 | 
			
		||||
    if (!fhss_structure) {
 | 
			
		||||
| 
						 | 
				
			
			@ -687,7 +753,7 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle,
 | 
			
		|||
            fhss_failed_handle_remove(fhss_structure, handle);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        fhss_failed_tx->bad_channel = fhss_structure->rx_channel;
 | 
			
		||||
        fhss_failed_tx->bad_channel = channel;
 | 
			
		||||
    } else {
 | 
			
		||||
        // Create new failure handle and return true to retransmit
 | 
			
		||||
        fhss_failed_handle_add(fhss_structure, handle, fhss_structure->rx_channel);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,10 @@
 | 
			
		|||
 * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts
 | 
			
		||||
 */
 | 
			
		||||
#define WS_NUMBER_OF_CHANNEL_RETRIES    4
 | 
			
		||||
//TX/RX slot length in milliseconds
 | 
			
		||||
#define WS_MAX_TXRX_SLOT_LEN_MS         100
 | 
			
		||||
// 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
 | 
			
		||||
// 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
 | 
			
		||||
| 
						 | 
				
			
			@ -55,5 +57,6 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
 | 
			
		|||
int fhss_ws_remove_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8]);
 | 
			
		||||
int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_configuration_t *fhss_configuration);
 | 
			
		||||
int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_count);
 | 
			
		||||
void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure);
 | 
			
		||||
 | 
			
		||||
#endif /*FHSS_WS_H_*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -842,7 +842,7 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr)
 | 
			
		|||
    if (retval != 0) {
 | 
			
		||||
        tr_warn("dhcp service socket_sendto fails: %i", retval);
 | 
			
		||||
    } else {
 | 
			
		||||
        tr_debug("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address));
 | 
			
		||||
        tr_info("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
bool dhcp_service_timer_tick(uint16_t ticks)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,17 +49,81 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void)
 | 
			
		|||
    }
 | 
			
		||||
    entry->serverDynamic_DUID = server_duid_ptr;
 | 
			
		||||
    entry->serverDynamic_DUID_length = 16;
 | 
			
		||||
    entry->clientIdSequence = 0;
 | 
			
		||||
    entry->firstFreedId = 0;
 | 
			
		||||
    entry->firstUnusedId = DHCP_ADDRESS_ID_START;
 | 
			
		||||
    entry->enableAddressAutonous = true;
 | 
			
		||||
    entry->clientIdDefaultSuffics = 0x0000000;
 | 
			
		||||
    entry->maxSuppertedClients = 200;
 | 
			
		||||
    entry->disableAddressListAllocation = false;
 | 
			
		||||
    entry->maxSupportedClients = 200;
 | 
			
		||||
    entry->validLifetime = 7200;
 | 
			
		||||
    entry->removeCb = NULL;
 | 
			
		||||
    entry->addCb = NULL;
 | 
			
		||||
    ns_list_init(&entry->allocatedAddressList);
 | 
			
		||||
    return entry;
 | 
			
		||||
}
 | 
			
		||||
static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_alloacted_address_entry_t *entry)
 | 
			
		||||
 | 
			
		||||
static uint16_t libdhcpv6_get_next_freed_id(dhcpv6_gua_server_entry_s *serverInfo)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t last_allocated_id = DHCP_ADDRESS_ID_START - 1;
 | 
			
		||||
    ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
 | 
			
		||||
        if (last_allocated_id + 1 == cur->allocatedID) {
 | 
			
		||||
            //Last and current plus 1 so normal order
 | 
			
		||||
            last_allocated_id = cur->allocatedID;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((cur->allocatedID - last_allocated_id) == 2) {
 | 
			
		||||
            //one missing sequence between last and current
 | 
			
		||||
            if (last_allocated_id + 1 == serverInfo->firstFreedId) {
 | 
			
		||||
                //Skip Current freedID this will update after this call to new one
 | 
			
		||||
                last_allocated_id = cur->allocatedID;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (last_allocated_id + 1 == serverInfo->firstFreedId) {
 | 
			
		||||
            //Skip first if it is last freedId
 | 
			
		||||
            return last_allocated_id + 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return last_allocated_id + 1;
 | 
			
		||||
    }
 | 
			
		||||
    //No more freed ID so return 0
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint16_t libdhcpv6_address_id_allocate(dhcpv6_gua_server_entry_s *serverInfo)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t address_id;
 | 
			
		||||
    if (serverInfo->firstFreedId) {
 | 
			
		||||
        address_id = serverInfo->firstFreedId;
 | 
			
		||||
        //Discover next free freed possible value
 | 
			
		||||
        serverInfo->firstFreedId = libdhcpv6_get_next_freed_id(serverInfo);
 | 
			
		||||
    } else {
 | 
			
		||||
        //Allocated new ID
 | 
			
		||||
        address_id = serverInfo->firstUnusedId++;
 | 
			
		||||
    }
 | 
			
		||||
    return address_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void libdhcpv6_gen_suffics_from_eui48(uint8_t *ptr, uint8_t *eui48)
 | 
			
		||||
{
 | 
			
		||||
    *ptr++  = *eui48++ ^ 2;
 | 
			
		||||
    *ptr++  = *eui48++;
 | 
			
		||||
    *ptr++  = *eui48++;
 | 
			
		||||
    *ptr++  = 0xff;
 | 
			
		||||
    *ptr++  = 0xfe;
 | 
			
		||||
    *ptr++  = *eui48++;
 | 
			
		||||
    *ptr++  = *eui48++;
 | 
			
		||||
    *ptr    = *eui48++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void libdhcpv6_gen_suffics_from_allocated_id(uint8_t *ptr, uint8_t *server_unique_48_bit_id, uint16_t allocated_id)
 | 
			
		||||
{
 | 
			
		||||
    memcpy(ptr, server_unique_48_bit_id, 6);
 | 
			
		||||
    common_write_16_bit(allocated_id, ptr + 6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static uint16_t libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_t *entry)
 | 
			
		||||
{
 | 
			
		||||
    //GENERATE ADDRESS
 | 
			
		||||
    uint8_t *ptr = entry->nonTemporalAddress;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,25 +134,78 @@ static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dh
 | 
			
		|||
                entry->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
 | 
			
		||||
            memcpy(ptr, entry->linkId, 8);
 | 
			
		||||
            *ptr ^= 2;
 | 
			
		||||
        } else if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
 | 
			
		||||
            *ptr++  = entry->linkId[0] ^ 2;
 | 
			
		||||
            *ptr++  = entry->linkId[1];
 | 
			
		||||
            *ptr++  = entry->linkId[2];
 | 
			
		||||
            *ptr++  = 0xff;
 | 
			
		||||
            *ptr++  = 0xfe;
 | 
			
		||||
            *ptr++  = entry->linkId[3];
 | 
			
		||||
            *ptr++  = entry->linkId[4];
 | 
			
		||||
            *ptr    = entry->linkId[5];
 | 
			
		||||
        } else {
 | 
			
		||||
            ptr = common_write_32_bit((serverInfo->clientIdDefaultSuffics | 02000000), ptr);
 | 
			
		||||
            ptr = common_write_32_bit((serverInfo->clientIdSequence + 2), ptr);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        ptr = common_write_32_bit((serverInfo->clientIdDefaultSuffics | 02000000), ptr);
 | 
			
		||||
        ptr = common_write_32_bit((serverInfo->clientIdSequence + 2), ptr);
 | 
			
		||||
        if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
 | 
			
		||||
            libdhcpv6_gen_suffics_from_eui48(ptr, entry->linkId);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    serverInfo->clientIdSequence++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t allocated_id = libdhcpv6_address_id_allocate(serverInfo);
 | 
			
		||||
    libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, allocated_id);
 | 
			
		||||
    return allocated_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void libdhcpv6_address_free(dhcpv6_gua_server_entry_s *server_info, dhcpv6_allocated_address_entry_t *entry)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_remove(&server_info->allocatedAddressList, entry);
 | 
			
		||||
    if (!server_info->enableAddressAutonous) {
 | 
			
		||||
        if (entry->allocatedID + 1 == server_info->firstUnusedId) {
 | 
			
		||||
            server_info->firstUnusedId--;
 | 
			
		||||
        } else if (server_info->firstFreedId == 0 || server_info->firstFreedId > entry->allocatedID) {
 | 
			
		||||
            server_info->firstFreedId = entry->allocatedID;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ns_dyn_mem_free(entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo)
 | 
			
		||||
{
 | 
			
		||||
    memcpy(ptr, serverInfo->guaPrefix, 8);
 | 
			
		||||
    ptr += 8;
 | 
			
		||||
    if (serverInfo->enableAddressAutonous) {
 | 
			
		||||
        //Generate address from link layer address
 | 
			
		||||
        if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
 | 
			
		||||
                address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
 | 
			
		||||
            memcpy(ptr, address->linkId, 8);
 | 
			
		||||
            *ptr ^= 2;
 | 
			
		||||
            return;
 | 
			
		||||
        } else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
 | 
			
		||||
            libdhcpv6_gen_suffics_from_eui48(ptr, address->linkId);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    //Generate from 16-bit allocate and default suffic's
 | 
			
		||||
    libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, address->allocatedID);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool libdhcpv6_address_suffics_compare(const uint8_t *suffics, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t allocated_suffics[8];
 | 
			
		||||
    if (serverInfo->enableAddressAutonous) {
 | 
			
		||||
        //Generate address from link layer address
 | 
			
		||||
        if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
 | 
			
		||||
                address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
 | 
			
		||||
            memcpy(allocated_suffics, address->linkId, 8);
 | 
			
		||||
            allocated_suffics[0] ^= 2;
 | 
			
		||||
            goto compare_suffics;
 | 
			
		||||
        } else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
 | 
			
		||||
            libdhcpv6_gen_suffics_from_eui48(allocated_suffics, address->linkId);
 | 
			
		||||
            goto compare_suffics;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    //Generate from 16-bit allocate and default suffic's
 | 
			
		||||
    libdhcpv6_gen_suffics_from_allocated_id(allocated_suffics, serverInfo->clientIdDefaultSuffics, address->allocatedID);
 | 
			
		||||
 | 
			
		||||
compare_suffics:
 | 
			
		||||
    if (memcmp(allocated_suffics, suffics, 8)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,15 +214,16 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds)
 | 
			
		|||
    //Check All allocated server inside this loop
 | 
			
		||||
    ns_list_foreach(dhcpv6_gua_server_entry_s, cur, &dhcpv6_gua_server_list) {
 | 
			
		||||
        //Check All allocated address in this module
 | 
			
		||||
        ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, address, &cur->allocatedAddressList) {
 | 
			
		||||
        ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, address, &cur->allocatedAddressList) {
 | 
			
		||||
            //Update
 | 
			
		||||
            if (address->preferredLifetime) {
 | 
			
		||||
                if (address->preferredLifetime <= timeUpdateInSeconds) {
 | 
			
		||||
                    //Stop use this address for leasequery and delete Route or address map
 | 
			
		||||
 | 
			
		||||
                    address->preferredLifetime = 0;
 | 
			
		||||
                    if (cur->removeCb) {
 | 
			
		||||
                        cur->removeCb(cur->interfaceId, address->nonTemporalAddress, cur->guaPrefix);
 | 
			
		||||
                        uint8_t allocated_address[16];
 | 
			
		||||
                        libdhcpv6_allocated_address_write(allocated_address, address, cur);
 | 
			
		||||
                        cur->removeCb(cur->interfaceId, allocated_address, cur->guaPrefix);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    address->preferredLifetime -= timeUpdateInSeconds;
 | 
			
		||||
| 
						 | 
				
			
			@ -113,8 +231,7 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds)
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            if (address->lifetime <= timeUpdateInSeconds) {
 | 
			
		||||
                ns_list_remove(&cur->allocatedAddressList, address);
 | 
			
		||||
                ns_dyn_mem_free(address);
 | 
			
		||||
                libdhcpv6_address_free(cur, address);
 | 
			
		||||
            } else {
 | 
			
		||||
                address->lifetime -= timeUpdateInSeconds;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -187,6 +304,15 @@ dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t
 | 
			
		|||
        duid_length = libdhcpv6_duid_linktype_size(serverDUIDType) + 2;
 | 
			
		||||
        ptr = common_write_16_bit(serverDUIDType, ptr);
 | 
			
		||||
        memcpy(ptr, serverDUID, libdhcpv6_duid_linktype_size(serverDUIDType));
 | 
			
		||||
        //SET Defaultsuffics
 | 
			
		||||
        if (libdhcpv6_duid_linktype_size(serverDUIDType) == 8) {
 | 
			
		||||
            memcpy(entry->clientIdDefaultSuffics, serverDUID, 3);
 | 
			
		||||
            memcpy(entry->clientIdDefaultSuffics + 3, serverDUID + 5, 3);
 | 
			
		||||
        } else {
 | 
			
		||||
            memcpy(entry->clientIdDefaultSuffics, serverDUID, 6);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        entry->clientIdDefaultSuffics[0] ^= 0x02;
 | 
			
		||||
 | 
			
		||||
        //SET DUID
 | 
			
		||||
        if (libdhcpv6_server_duid_set(entry, duid_ll, DHCPV6_DUID_LINK_LAYER_TYPE, duid_length) != 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +334,7 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t
 | 
			
		|||
    dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefix);
 | 
			
		||||
    if (serverInfo) {
 | 
			
		||||
        if ((serverInfo->interfaceId == interfaceId) && (memcmp(serverInfo->guaPrefix, prefix, 8) == 0)) {
 | 
			
		||||
            ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
            ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
                ns_list_remove(&serverInfo->allocatedAddressList, cur);
 | 
			
		||||
                ns_dyn_mem_free(cur);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -219,10 +345,8 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dhcpv6_alloacted_address_entry_t *libdhcpv6_address_entry_allocate(uint32_t validLifetime)
 | 
			
		||||
static void libdhcpv6_address_entry_lifetime_set(dhcpv6_allocated_address_entry_t *entry, uint32_t validLifetime)
 | 
			
		||||
{
 | 
			
		||||
    dhcpv6_alloacted_address_entry_t *entry = ns_dyn_mem_alloc(sizeof(dhcpv6_alloacted_address_entry_t));
 | 
			
		||||
    if (entry) {
 | 
			
		||||
    if (validLifetime != 0xffffffff) {
 | 
			
		||||
        entry->lifetime = validLifetime;
 | 
			
		||||
        entry->preferredLifetime = (validLifetime >> 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -230,15 +354,43 @@ static dhcpv6_alloacted_address_entry_t *libdhcpv6_address_entry_allocate(uint32
 | 
			
		|||
        entry->lifetime = 0xffffffff;
 | 
			
		||||
        entry->preferredLifetime = 0xffffffff;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
    return entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address)
 | 
			
		||||
static void libdhcpv6_copy_allocated_entry_to_temp(dhcpv6_allocated_address_entry_t *cur, dhcpv6_allocated_address_t *address, dhcpv6_gua_server_entry_s *serverInfo)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
        if (memcmp(cur->nonTemporalAddress, address, 16) == 0) {
 | 
			
		||||
            return cur;
 | 
			
		||||
    libdhcpv6_allocated_address_write(address->nonTemporalAddress, cur, serverInfo);
 | 
			
		||||
    memcpy(address->linkId, cur->linkId, 8);
 | 
			
		||||
    address->T0 = cur->T0;
 | 
			
		||||
    address->T1 = cur->T1;
 | 
			
		||||
    address->iaID = cur->iaID;
 | 
			
		||||
    address->lifetime = cur->lifetime;
 | 
			
		||||
    address->preferredLifetime = cur->preferredLifetime;
 | 
			
		||||
    address->linkType = cur->linkType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void libdhcpv6_copy_temp_to_allocated_entry(dhcpv6_allocated_address_entry_t *cur, dhcpv6_allocated_address_t *address, uint16_t allocated_id)
 | 
			
		||||
{
 | 
			
		||||
    memcpy(cur->linkId, address->linkId, 8);
 | 
			
		||||
    cur->allocatedID = allocated_id;
 | 
			
		||||
    cur->T0 = address->T0;
 | 
			
		||||
    cur->T1 = address->T1;
 | 
			
		||||
    cur->iaID = address->iaID;
 | 
			
		||||
    cur->lifetime = address->lifetime;
 | 
			
		||||
    cur->preferredLifetime = address->preferredLifetime;
 | 
			
		||||
    cur->linkType = address->linkType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dhcpv6_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address)
 | 
			
		||||
{
 | 
			
		||||
    if (memcmp(serverInfo->guaPrefix, address, 8)) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
        if (libdhcpv6_address_suffics_compare(address + 8, cur, serverInfo) == 0) {
 | 
			
		||||
            libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo);
 | 
			
		||||
            return &serverInfo->tempAddressEntry;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -246,49 +398,95 @@ dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcp
 | 
			
		|||
 | 
			
		||||
void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address)
 | 
			
		||||
{
 | 
			
		||||
    ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
        if (memcmp(cur->nonTemporalAddress, address, 16) == 0) {
 | 
			
		||||
            ns_list_remove(&serverInfo->allocatedAddressList, cur);
 | 
			
		||||
            ns_dyn_mem_free(cur);
 | 
			
		||||
    if (memcmp(serverInfo->guaPrefix, address, 8)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
        if (libdhcpv6_address_suffics_compare(address + 8, cur, serverInfo) == 0) {
 | 
			
		||||
            libdhcpv6_address_free(serverInfo, cur);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew)
 | 
			
		||||
 | 
			
		||||
static void libdhcpv6_address_id_add_to_list(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_entry_t *allocated)
 | 
			
		||||
{
 | 
			
		||||
    dhcpv6_alloacted_address_entry_t *newEntry = NULL;
 | 
			
		||||
    if (serverInfo->firstUnusedId != allocated->allocatedID + 1) {
 | 
			
		||||
        ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
            if (cur->allocatedID > allocated->allocatedID) {
 | 
			
		||||
                //Add before new allocated
 | 
			
		||||
                if (cur->link.prev) {
 | 
			
		||||
                    ns_list_add_before(&serverInfo->allocatedAddressList, cur, allocated);
 | 
			
		||||
                } else {
 | 
			
		||||
                    //New first
 | 
			
		||||
                    ns_list_add_to_start(&serverInfo->allocatedAddressList, allocated);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ns_list_add_to_end(&serverInfo->allocatedAddressList, allocated);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew)
 | 
			
		||||
{
 | 
			
		||||
    dhcpv6_allocated_address_t *newEntry = NULL;
 | 
			
		||||
    dhcpv6_allocated_address_entry_t *allocatedEntry = NULL;
 | 
			
		||||
    uint16_t duiLength = 6;
 | 
			
		||||
    if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
 | 
			
		||||
            linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
 | 
			
		||||
        duiLength = 8;
 | 
			
		||||
    }
 | 
			
		||||
    ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
 | 
			
		||||
    if (serverInfo->enableAddressAutonous && serverInfo->disableAddressListAllocation) {
 | 
			
		||||
        //Accept allways when autonous
 | 
			
		||||
        newEntry = &serverInfo->tempAddressEntry;
 | 
			
		||||
        allocateNew = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
 | 
			
		||||
        if (cur->linkType == linkType) {
 | 
			
		||||
            if (memcmp(cur->linkId, linkId, duiLength) == 0) {
 | 
			
		||||
                cur->iaID = iaID;
 | 
			
		||||
                if (serverInfo->validLifetime != 0xffffffff) {
 | 
			
		||||
                    cur->lifetime = serverInfo->validLifetime ;
 | 
			
		||||
                    cur->preferredLifetime = (serverInfo->validLifetime  >> 1);
 | 
			
		||||
                } else {
 | 
			
		||||
                    cur->lifetime = 0xffffffff;
 | 
			
		||||
                    cur->preferredLifetime = 0xffffffff;
 | 
			
		||||
                }
 | 
			
		||||
                return cur;
 | 
			
		||||
                libdhcpv6_address_entry_lifetime_set(cur, serverInfo->validLifetime);
 | 
			
		||||
                libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo);
 | 
			
		||||
                return &serverInfo->tempAddressEntry;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (allocateNew) {
 | 
			
		||||
        if (ns_list_count(&serverInfo->allocatedAddressList) < serverInfo->maxSuppertedClients) {
 | 
			
		||||
            newEntry = libdhcpv6_address_entry_allocate(serverInfo->validLifetime);
 | 
			
		||||
        if (ns_list_count(&serverInfo->allocatedAddressList) < serverInfo->maxSupportedClients) {
 | 
			
		||||
            allocatedEntry = ns_dyn_mem_alloc(sizeof(dhcpv6_allocated_address_entry_t));
 | 
			
		||||
            if (allocatedEntry) {
 | 
			
		||||
                newEntry = &serverInfo->tempAddressEntry;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (newEntry) {
 | 
			
		||||
 | 
			
		||||
        if (serverInfo->validLifetime != 0xffffffff) {
 | 
			
		||||
            newEntry->lifetime = serverInfo->validLifetime;
 | 
			
		||||
            newEntry->preferredLifetime = (serverInfo->validLifetime >> 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            newEntry->lifetime = 0xffffffff;
 | 
			
		||||
            newEntry->preferredLifetime = 0xffffffff;
 | 
			
		||||
        }
 | 
			
		||||
        memcpy(newEntry->linkId, linkId, duiLength);
 | 
			
		||||
        newEntry->linkType = linkType;
 | 
			
		||||
        newEntry->iaID = iaID;
 | 
			
		||||
        newEntry->T0 = T0;
 | 
			
		||||
        newEntry->T1 = T1;
 | 
			
		||||
                libdhcpv6_address_generate(serverInfo, newEntry);
 | 
			
		||||
                ns_list_add_to_end(&serverInfo->allocatedAddressList, newEntry);
 | 
			
		||||
        uint16_t allocated_id = libdhcpv6_address_generate(serverInfo, newEntry);
 | 
			
		||||
        if (!serverInfo->disableAddressListAllocation) {
 | 
			
		||||
            libdhcpv6_copy_temp_to_allocated_entry(allocatedEntry, newEntry, allocated_id);
 | 
			
		||||
            if (serverInfo->enableAddressAutonous) {
 | 
			
		||||
                ns_list_add_to_end(&serverInfo->allocatedAddressList, allocatedEntry);
 | 
			
		||||
            } else {
 | 
			
		||||
                //Add to list to proper order
 | 
			
		||||
                libdhcpv6_address_id_add_to_list(serverInfo, allocatedEntry);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,9 +28,25 @@
 | 
			
		|||
 | 
			
		||||
#include "libDHCPv6/libDHCPv6.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_SUPPORTED_ADDRESS_LIST_SIZE 0x0000fffd
 | 
			
		||||
#define DHCP_ADDRESS_ID_START 2
 | 
			
		||||
 | 
			
		||||
typedef void (dhcp_address_prefer_remove_cb)(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info);
 | 
			
		||||
 | 
			
		||||
typedef struct dhcpv6_alloacted_address_entry_s {
 | 
			
		||||
typedef struct dhcpv6_allocated_address_entry_s {
 | 
			
		||||
    uint8_t             linkId[8];  /*!< Services UL64 */
 | 
			
		||||
    uint32_t            iaID;
 | 
			
		||||
    uint32_t            T0;
 | 
			
		||||
    uint32_t            T1;
 | 
			
		||||
    uint32_t            preferredLifetime;
 | 
			
		||||
    uint32_t            lifetime;
 | 
			
		||||
    uint16_t            linkType;
 | 
			
		||||
    uint16_t            allocatedID;
 | 
			
		||||
    ns_list_link_t      link;               /*!< List link entry */
 | 
			
		||||
} dhcpv6_allocated_address_entry_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct dhcpv6_allocated_address_s {
 | 
			
		||||
    uint8_t             nonTemporalAddress[16];
 | 
			
		||||
    uint8_t             linkId[8];  /*!< Services UL64 */
 | 
			
		||||
    uint16_t            linkType;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,18 +55,9 @@ typedef struct dhcpv6_alloacted_address_entry_s {
 | 
			
		|||
    uint32_t            T1;
 | 
			
		||||
    uint32_t            preferredLifetime;
 | 
			
		||||
    uint32_t            lifetime;
 | 
			
		||||
    ns_list_link_t      link;               /*!< List link entry */
 | 
			
		||||
} dhcpv6_alloacted_address_entry_t;
 | 
			
		||||
} dhcpv6_allocated_address_t;
 | 
			
		||||
 | 
			
		||||
typedef NS_LIST_HEAD(dhcpv6_alloacted_address_entry_t, link) dhcpv6_alloacted_address_list_t;
 | 
			
		||||
 | 
			
		||||
typedef struct thread_dhcpv6_server_data_s {
 | 
			
		||||
    uint8_t           prefix[8];    /*!< Services Prefix */
 | 
			
		||||
    uint16_t          maxSuppertedClients;
 | 
			
		||||
    uint32_t          clientIdSequence;     /*!< Define  */
 | 
			
		||||
    dhcpv6_alloacted_address_list_t allocatedAddressList;
 | 
			
		||||
    ns_list_link_t      link;               /*!< List link entry */
 | 
			
		||||
} dhcpv6_server_data_entry_t;
 | 
			
		||||
typedef NS_LIST_HEAD(dhcpv6_allocated_address_entry_t, link) dhcpv6_allocated_address_list_t;
 | 
			
		||||
 | 
			
		||||
typedef struct dhcp_address_cache_update {
 | 
			
		||||
    uint8_t *allocatedAddress;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,19 +69,22 @@ typedef bool (dhcp_address_add_notify_cb)(int8_t interfaceId, dhcp_address_cache
 | 
			
		|||
 | 
			
		||||
typedef struct dhcpv6_gua_server_entry_s {
 | 
			
		||||
    int8_t                          interfaceId;
 | 
			
		||||
    bool                            enableAddressAutonous;
 | 
			
		||||
    bool                            enableAddressAutonous: 1;
 | 
			
		||||
    bool                            disableAddressListAllocation: 1;
 | 
			
		||||
    uint16_t                        socketInstance_id;
 | 
			
		||||
    uint8_t                         guaPrefix[8];
 | 
			
		||||
    uint8_t                         serverDynamic_DUID_length;
 | 
			
		||||
    uint32_t                        maxSuppertedClients;
 | 
			
		||||
    uint32_t                        clientIdDefaultSuffics;
 | 
			
		||||
    uint32_t                        clientIdSequence;       /*!< Define  */
 | 
			
		||||
    uint32_t                        maxSupportedClients;
 | 
			
		||||
    uint8_t                         clientIdDefaultSuffics[6];
 | 
			
		||||
    uint16_t                        firstFreedId;
 | 
			
		||||
    uint16_t                        firstUnusedId;  /*!< This is first unused Id */
 | 
			
		||||
    uint32_t                        validLifetime;
 | 
			
		||||
    dhcp_duid_options_params_t      serverDUID;
 | 
			
		||||
    uint8_t                         *serverDynamic_DUID;
 | 
			
		||||
    dhcp_address_prefer_remove_cb   *removeCb;
 | 
			
		||||
    dhcp_address_add_notify_cb *addCb;
 | 
			
		||||
    dhcpv6_alloacted_address_list_t allocatedAddressList;
 | 
			
		||||
    dhcpv6_allocated_address_list_t allocatedAddressList;
 | 
			
		||||
    dhcpv6_allocated_address_t  tempAddressEntry;
 | 
			
		||||
    ns_list_link_t      link;                   /*!< List link entry */
 | 
			
		||||
} dhcpv6_gua_server_entry_s;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,10 +94,11 @@ int libdhcpv6_server_duid_set(dhcpv6_gua_server_entry_s *server_info, uint8_t *d
 | 
			
		|||
void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t interfaceId);
 | 
			
		||||
void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds);
 | 
			
		||||
void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);
 | 
			
		||||
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);
 | 
			
		||||
dhcpv6_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);
 | 
			
		||||
dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_interfaceid(int8_t interfaceId, const uint8_t *prefixPtr);
 | 
			
		||||
dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstance(uint16_t socketInstance, uint8_t *prefixPtr);
 | 
			
		||||
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew);
 | 
			
		||||
dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew);
 | 
			
		||||
void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo);
 | 
			
		||||
#else
 | 
			
		||||
#define libdhcpv6_gua_server_list_empty() true
 | 
			
		||||
#define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,6 +65,7 @@ int8_t net_6lowpan_nd_parameter_set(const nd_parameters_s *p)
 | 
			
		|||
 | 
			
		||||
    return 0;
 | 
			
		||||
#else
 | 
			
		||||
    (void) p;
 | 
			
		||||
    return -2;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +90,8 @@ int8_t net_6lowpan_nd_timer_base_tick_set(uint8_t base_tick_x_100ms)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    nd_base_tick = base_tick_x_100ms;
 | 
			
		||||
#else
 | 
			
		||||
    (void) base_tick_x_100ms;
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -103,5 +106,7 @@ void net_6lowpan_nd_parameter_read(nd_parameters_s *p)
 | 
			
		|||
{
 | 
			
		||||
#ifdef HAVE_6LOWPAN_ND
 | 
			
		||||
    *p = nd_params;
 | 
			
		||||
#else
 | 
			
		||||
    (void) p;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -146,6 +146,8 @@ int8_t net_load_balance_network_switch_cb_set(int8_t interface_id, net_load_bala
 | 
			
		|||
 | 
			
		||||
    return load_balance_network_switch_cb_set(interface_ptr->lb_api, network_switch_notify);
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    (void) network_switch_notify;
 | 
			
		||||
    return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +190,8 @@ int8_t net_load_balance_create(int8_t interface_id, bool  enable_periodic_beacon
 | 
			
		|||
 | 
			
		||||
    return 0;
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    (void) enable_periodic_beacon_interval;
 | 
			
		||||
    return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +209,7 @@ int8_t net_load_balance_delete(int8_t interface_id)
 | 
			
		|||
 | 
			
		||||
    return load_balance_delete(lb_api);
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -223,6 +228,9 @@ int8_t net_load_balance_threshold_set(int8_t interface_id, uint8_t threshold_min
 | 
			
		|||
 | 
			
		||||
    return load_balance_network_threshold_set(interface_ptr->lb_api, threshold_min, threshold_max);
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    (void) threshold_min;
 | 
			
		||||
    (void) threshold_max;
 | 
			
		||||
    return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -259,8 +267,10 @@ void net_load_balance_internal_state_activate(protocol_interface_info_entry_t *i
 | 
			
		|||
    set_req.value_pointer = &state;
 | 
			
		||||
    set_req.value_size = sizeof(bool);
 | 
			
		||||
    interface_ptr->mac_api->mlme_req(interface_ptr->mac_api, MLME_SET, &set_req);
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_ptr;
 | 
			
		||||
    (void) state;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RPL
 | 
			
		||||
| 
						 | 
				
			
			@ -361,6 +371,8 @@ int8_t net_load_balance_set_max_probability(int8_t interface_id, uint8_t max_p)
 | 
			
		|||
 | 
			
		||||
    return load_balance_set_max_probability(interface_ptr->lb_api, max_p);
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    (void) max_p;
 | 
			
		||||
    return -1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -400,6 +400,10 @@ int8_t arm_nwk_6lowpan_gp_address_mode(int8_t interface_id, net_6lowpan_gp_addre
 | 
			
		|||
 | 
			
		||||
    return 0;
 | 
			
		||||
#else
 | 
			
		||||
    (void) interface_id;
 | 
			
		||||
    (void) mode;
 | 
			
		||||
    (void) short_address_base;
 | 
			
		||||
    (void) define_new_short_address_at_DAD;
 | 
			
		||||
    return -2;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -903,6 +907,9 @@ int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_la
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_6LOWPAN_ND
 | 
			
		||||
    (void) mode;
 | 
			
		||||
    (void) sec_level;
 | 
			
		||||
    (void) psk_key_info;
 | 
			
		||||
    return -1;
 | 
			
		||||
#else
 | 
			
		||||
    if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,6 +108,8 @@ int8_t socket_close(int8_t sid)
 | 
			
		|||
int8_t socket_listen(int8_t socket, uint8_t backlog)
 | 
			
		||||
{
 | 
			
		||||
#ifdef NO_TCP
 | 
			
		||||
    (void) socket;
 | 
			
		||||
    (void) backlog;
 | 
			
		||||
    return -1;
 | 
			
		||||
#else
 | 
			
		||||
    socket_t *socket_ptr = socket_pointer_get(socket);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +143,9 @@ int8_t socket_listen(int8_t socket, uint8_t backlog)
 | 
			
		|||
int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_fptr)(void *))
 | 
			
		||||
{
 | 
			
		||||
#ifdef NO_TCP
 | 
			
		||||
    (void) listen_socket_id;
 | 
			
		||||
    (void) addr;
 | 
			
		||||
    (void) passed_fptr;
 | 
			
		||||
    return -1;
 | 
			
		||||
#else
 | 
			
		||||
    socket_t *socket_ptr = socket_pointer_get(listen_socket_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +194,8 @@ int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_
 | 
			
		|||
int8_t socket_shutdown(int8_t socket, uint8_t how)
 | 
			
		||||
{
 | 
			
		||||
#ifdef NO_TCP
 | 
			
		||||
    (void) socket;
 | 
			
		||||
    (void) how;
 | 
			
		||||
    return -1;
 | 
			
		||||
#else
 | 
			
		||||
    socket_t *socket_ptr = socket_pointer_get(socket);
 | 
			
		||||
| 
						 | 
				
			
			@ -608,8 +615,8 @@ int8_t socket_connect(int8_t socket, ns_address_t *address, uint8_t randomly_tak
 | 
			
		|||
 | 
			
		||||
        socket_ptr->flags |= SOCKET_FLAG_CONNECTING;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
exit:
 | 
			
		||||
#endif
 | 
			
		||||
    if (status != 0) {
 | 
			
		||||
        memcpy(inet_pcb->remote_address, ns_in6addr_any, 16);
 | 
			
		||||
        inet_pcb->remote_port = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,6 +136,7 @@ SRCS += \
 | 
			
		|||
	source/Service_Libs/fhss/fhss_common.c \
 | 
			
		||||
	source/Service_Libs/fhss/channel_functions.c \
 | 
			
		||||
	source/Service_Libs/fhss/channel_list.c \
 | 
			
		||||
	source/Service_Libs/fhss/fhss_test_api.c \
 | 
			
		||||
	source/Service_Libs/fnv_hash/fnv_hash.c \
 | 
			
		||||
	source/Service_Libs/hmac/hmac_sha1.c \
 | 
			
		||||
	source/Service_Libs/ieee_802_11/ieee_802_11.c \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue