diff --git a/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp b/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp index 58932e45a7e..b65e1ebdd4a 100644 --- a/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp +++ b/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/nanostack/fhss_api.h b/features/nanostack/sal-stack-nanostack/nanostack/fhss_api.h index 84c0c17c326..be5a90c1d21 100644 --- a/features/nanostack/sal-stack-nanostack/nanostack/fhss_api.h +++ b/features/nanostack/sal-stack-nanostack/nanostack/fhss_api.h @@ -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. diff --git a/features/nanostack/sal-stack-nanostack/nanostack/fhss_test_api.h b/features/nanostack/sal-stack-nanostack/nanostack/fhss_test_api.h new file mode 100644 index 00000000000..270c5a27a31 --- /dev/null +++ b/features/nanostack/sal-stack-nanostack/nanostack/fhss_test_api.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/nanostack/platform/arm_hal_phy.h b/features/nanostack/sal-stack-nanostack/nanostack/platform/arm_hal_phy.h index 9f4e09937db..ab53b5942cb 100644 --- a/features/nanostack/sal-stack-nanostack/nanostack/platform/arm_hal_phy.h +++ b/features/nanostack/sal-stack-nanostack/nanostack/platform/arm_hal_phy.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 */ diff --git a/features/nanostack/sal-stack-nanostack/nanostack/sw_mac.h b/features/nanostack/sal-stack-nanostack/nanostack/sw_mac.h index e4a018fc4e9..894b8b75c4b 100644 --- a/features/nanostack/sal-stack-nanostack/nanostack/sw_mac.h +++ b/features/nanostack/sal-stack-nanostack/nanostack/sw_mac.h @@ -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. diff --git a/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h b/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h index a4d4d460e8f..1559f433d55 100644 --- a/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h +++ b/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h @@ -48,14 +48,10 @@ int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id); /** * Border router configuration options */ -#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_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 */ +#define BBR_DEFAULT_ROUTE 0x0008 /**< Add default route parameter to DIO */ /** * Configure border router features. diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index e78b91c088a..cbe3e12c67e 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c index d3b0d16520b..92ea3ce7382 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c @@ -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); - } + 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; + protocol_mac_reset(cur); cur->interface_mode = INTERFACE_IDLE; net_load_balance_internal_state_activate(cur, false); } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h index bd7875c5146..017805735ca 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h @@ -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_ */ diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c index 1f7de87fc7d..e33c7fe6f95 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c @@ -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; } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_response_handler.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_response_handler.c index 1c89a92578c..87d3003bbc6 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_response_handler.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_response_handler.c @@ -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); } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ND/nd_router_object.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ND/nd_router_object.c index c397bfa66c8..53ff5ac59f1 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ND/nd_router_object.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ND/nd_router_object.c @@ -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,11 +928,13 @@ 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)) { - aro_out->present = true; - aro_out->status = ARO_FULL; - return true; + 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; + return true; + } } /* We need to have entry in the Neighbour Cache */ @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_bootstrap.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_bootstrap.c index 84d0609fb28..483932b5781 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_bootstrap.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_common.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_common.c index 7bbfb739617..bfea2ba7a9e 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_common.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_common.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c index 435ab513345..7409f53a907 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_mle_message_handler.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_mle_message_handler.c index a8253c5f8eb..31e2f3416ca 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -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 */ diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_network_synch.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_network_synch.c index 0ef70d38f18..1ffbdc8da97 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_network_synch.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_network_synch.c @@ -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) diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_router_bootstrap.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_router_bootstrap.c index 1f17c7e5696..81d54494475 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_router_bootstrap.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_router_bootstrap.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c index 26b7dd9250a..bc137b1a9f0 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c index 0758ed4d123..99636719d9d 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c @@ -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)) { - lowpan_adaptation_tx_queue_write(interface_ptr, buf); - return 0; //Return here - } + + if (!lowpan_buffer_tx_allowed(interface_ptr, buf)) { + lowpan_adaptation_tx_queue_write(interface_ptr, buf); + 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 { - active_direct_confirm = false; - tx_ptr = lowpan_indirect_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue); + 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; + } + } } 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); diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h index 562e4820340..307dd9917be 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c index 390de439329..7961f10cc95 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c @@ -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 */ - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false); + 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); } - ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0); - + 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,9 +498,11 @@ 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 (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; + 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); @@ -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; - backbone_interface_id = -1; + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (!protocol_6lowpan_rpl_domain) { - return; - } + ws_bbr_routing_stop(cur); - rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); - protocol_6lowpan_rpl_root_dodag = NULL; + backbone_interface_id = -1; 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; diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h index 5da59eabcfb..b07565a96c2 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c index 44ae29e955c..6aaffc1a8ec 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c @@ -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); - tr_info("NUD generate NS %u", neighbor->index); + 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; - + fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); 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); - } + return -1; } + ns_sw_mac_fhss_register(cur->mac_api, fhss_api); } 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)); } - - fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; + // 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) { + if (!ws_neighbour || !etx_entry) { 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 - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + 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 (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)) { - 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 - return false; - } + //NUD Not needed for if neighbour is not parent candidate + return false; } if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) { @@ -1666,33 +1638,29 @@ 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_probe_parent_candidate(cur, ll_address)) { + return false; + } - 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)) { - 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) { - //tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); + 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) { + //tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); + activate_nud = true; + } else if (time_from_start > time_block) { + uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); + //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 + if (switch_prob < 2) { + //tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); activate_nud = true; - } else if (time_from_start > time_block) { - uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); - //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 - if (switch_prob < 2) { - //tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); - activate_nud = true; - } } } } @@ -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 0 + 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_rpl_dio_new_parent_accept(cur)) { + if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { + //Not proped yet because ETX is 0xffff return false; } - //Discover Multicast temporary entry + 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); - // 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); + //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; } - 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); - async_req.security.KeyIndex = mac_helper_default_key_index_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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h index 9d7f5524659..062dc767a3b 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c index 449a4d8e0d8..f89fbaa7483 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c @@ -22,6 +22,7 @@ #include "randLIB.h" #include #include +#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); - } + 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; diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h index a901d08b27d..588902753ff 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h index f9f07fe7011..92f7da38eb4 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h index 9ff0007021b..e7afc90d982 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c index 00523518eb0..9e94dbbe4cb 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c index e8be8dac519..63f7322326a 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c @@ -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; + } - cur->ws_info->fhss_uc_channel_function = channel_function; if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) { - cur->ws_info->fhss_uc_fixed_channel = 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; } - cur->ws_info->fhss_uc_dwell_interval = dwell_interval; + 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"); } - cur->ws_info->fhss_bc_channel_function = channel_function; + 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) { - cur->ws_info->fhss_bc_fixed_channel = 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; } - cur->ws_info->fhss_bc_dwell_interval = dwell_interval; - cur->ws_info->fhss_bc_interval = broadcast_interval; + 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); } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h index 2a0cbe2c122..c381b43f50e 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c index aeac1065314..01ffea56039 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c @@ -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 { - randLIB_get_n_bytes_random(gtk_value, GTK_LEN); + 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,9 +1004,22 @@ 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) { - // 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)); + + /* 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)); diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h index 5c0f35d9609..04bd157d789 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h @@ -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;} diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c index 6db0877be7f..f5bc4dba922 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c @@ -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); } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c index 22d95b8086d..455ba76f64b 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c @@ -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) { diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h index 90ba1481266..3ee6f10d0f3 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h @@ -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 * diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c index d7f2d23861a..7f833430a61 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -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++) { diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c index 452f5993aef..db891dc6e4a 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c @@ -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 + +// 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 -#define TRICKLE_IMIN_180_SECS 180 +// 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 */ - .k = 0, /* infinity - no consistency checking */ - .TimerExpirations = 3 + .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 = 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,20 +856,69 @@ 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 (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) { - if (ws_pae_supp_initial_key_send(pae_supp) < 0) { - tr_info("EAPOL-Key send failed"); + 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"); + } + } + + /* 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); } - } - // Maximum number of trickle expires, authentication fails - if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) { - ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); } } @@ -846,16 +940,76 @@ 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"); } - - // Starts trickle - pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; - 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_trickle_timer_start(pae_supp); } } } } +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) { pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); @@ -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) diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.h index bc8fc0f0110..458ed7bf9ea 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c index 5222fde7689..f0b3dc59eab 100644 --- a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c +++ b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c @@ -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); } diff --git a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.h b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.h index c209e2af427..3ae2aa14edf 100644 --- a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.h +++ b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.h @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6_radv.c b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6_radv.c index fff4edec989..446d05f38ec 100644 --- a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6_radv.c +++ b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6_radv.c @@ -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 { diff --git a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c index fe3102591d7..11df4aafa45 100644 --- a/features/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c +++ b/features/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c @@ -773,6 +773,9 @@ static buffer_t *ipv6_tunnel_exit(buffer_t *buf, uint8_t *payload) 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 @@ static buffer_t *ipv6_handle_options(buffer_t *buf, protocol_interface_info_entr 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); diff --git a/features/nanostack/sal-stack-nanostack/source/Core/buffer_dyn.c b/features/nanostack/sal-stack-nanostack/source/Core/buffer_dyn.c index 1b34e649973..268ee815ab9 100644 --- a/features/nanostack/sal-stack-nanostack/source/Core/buffer_dyn.c +++ b/features/nanostack/sal-stack-nanostack/source/Core/buffer_dyn.c @@ -16,7 +16,8 @@ */ #include "nsconfig.h" -#include "string.h" +#include +#include #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; - // Note - as well as this alloc+init, buffers can also be "realloced" - // in buffer_headroom() + 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); + } - 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; diff --git a/features/nanostack/sal-stack-nanostack/source/Core/include/ns_buffer.h b/features/nanostack/sal-stack-nanostack/source/Core/include/ns_buffer.h index 7ebb6e05454..b33148a14d1 100644 --- a/features/nanostack/sal-stack-nanostack/source/Core/include/ns_buffer.h +++ b/features/nanostack/sal-stack-nanostack/source/Core/include/ns_buffer.h @@ -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)) diff --git a/features/nanostack/sal-stack-nanostack/source/Core/ns_socket.c b/features/nanostack/sal-stack-nanostack/source/Core/ns_socket.c index 24f7738c6fa..05961ccb5b1 100644 --- a/features/nanostack/sal-stack-nanostack/source/Core/ns_socket.c +++ b/features/nanostack/sal-stack-nanostack/source/Core/ns_socket.c @@ -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 { diff --git a/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c b/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c index c2f567e40f7..a7755034a9d 100644 --- a/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -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; - } } - return retVal; + serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; + } + + 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 { - serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); - if (serverInfo) { - serverInfo->validLifetime = validLifeTimne; - retVal = 0; - } + return -2; } - return retVal; + serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; + } + serverInfo->validLifetime = validLifeTimne; + + 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; } diff --git a/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h b/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h index 2a236ad2542..8f8616f4f41 100644 --- a/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/features/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h index 7d534595458..acc45a67880 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c index 3f09ca01baf..fd56ecbd74a 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c @@ -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; } diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 1ea990f2e05..6442290a48e 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c index 5d1f5e48c92..b091da2a85f 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c index a7a5cc2a89d..1b8eda12291 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -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); - sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0); + 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) { diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c index 8b22875a96d..27de7e89cbe 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -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; } diff --git a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c index ca52231bac2..a5b679eb284 100644 --- a/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c +++ b/features/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c @@ -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) { diff --git a/features/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c b/features/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c index 2d8c99f4c13..279bc7f0df6 100644 --- a/features/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c +++ b/features/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c @@ -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 { diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c index c6854e3f4e0..b17dce381e9 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c @@ -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_control_neighbor_delete_from_instance(interface, instance, ll_addr); + } +} - rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); - if (neighbour) { - rpl_delete_neighbour(instance, neighbour); - } +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,8 +574,13 @@ 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) { - tr_error("Root DODAG already exists"); - return NULL; + 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) { @@ -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 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r } } - /* 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 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r 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 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r /* 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 diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h index 7569bac9449..464e5c2a832 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h @@ -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); @@ -146,20 +151,28 @@ void rpl_control_delete_domain(rpl_domain_t *domain); void rpl_control_set_domain_on_interface(struct protocol_interface_info_entry *cur, rpl_domain_t *domain, bool downstream); void rpl_control_remove_domain_from_interface(struct protocol_interface_info_entry *cur); void rpl_control_free_domain_instances_from_interface(struct protocol_interface_info_entry *cur); -void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle); +void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle); /* Target publishing */ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime); 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); -uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list); +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 */ diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c index 607cca6168a..6f7a5dbfcb5 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c @@ -545,8 +545,7 @@ static rpl_dao_target_t *rpl_instance_choose_target_to_assign(rpl_instance_t *in */ 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 @@ static rpl_dao_target_t *rpl_instance_choose_target_to_assign(rpl_instance_t *in } } - /* 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) diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_mrhof.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_mrhof.c index bfff5aa0004..be3fd9a8229 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_mrhof.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_mrhof.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_objective.h b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_objective.h index 67c35fd7c80..7e8293a396a 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_objective.h +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_objective.h @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_of0.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_of0.c index aa6927c1f16..bfdee2a4962 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_of0.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_of0.c @@ -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. diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c index ec581c8bb42..f8b25d86f19 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c @@ -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) diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h index c51adc81cd1..13e25c492ca 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_structures.h b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_structures.h index 1d4dcc0c377..aadbc60c28e 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_structures.h +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_structures.h @@ -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*/ diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c index d3e4720b041..99377e6150c 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c @@ -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; - dodag->new_config_advertisment_count++; + 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,17 +1833,21 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) { return; } - // 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) { - 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; + /* 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 (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; diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.h b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.h index 2780f6729a9..b3b51b38bc6 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.h +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.h @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c b/features/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c index b4596c9f4af..f23517a62c0 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c b/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c index 40a5c2eccda..bc61ab1ac60 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -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,13 +159,15 @@ 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; data->eap_type = 0; 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->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); } diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index b80a43cc404..bac7ecceb4a 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -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 */ diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/features/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index 5c0a48393d1..02b32b729f2 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c b/features/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index 50a9691b33b..b4206f69b4f 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -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 diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c b/features/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c index ba56a7566c6..409546c3dc2 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.c b/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.c index 9a0d4c8a434..cdcc31de326 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.c +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.c @@ -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 */ diff --git a/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.h b/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.h index 4a14fc2b6ff..9df422934b9 100644 --- a/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.h +++ b/features/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_keys.h @@ -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_ */ diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.c index 5eaa8a1fa69..77e58d09ad6 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.c +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.c @@ -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. */ diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.h b/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.h index 60ffa25f81e..a6c957826c9 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.h +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/Trickle/trickle.h @@ -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_ */ diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/blacklist/blacklist.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/blacklist/blacklist.c index 25d06666389..f47b2097bff 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/blacklist/blacklist.c +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/blacklist/blacklist.c @@ -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); } } diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.c index 60dc5a91fce..639490981a6 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.c +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.c @@ -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,7 +93,9 @@ 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) { - entry->stored_diff_etx = entry->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; - etx_cache_entry_init(attribute_index); + entry->etx = etx; - // 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); + 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; + 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; } } - } else { - //Accelerated ETX at for new neighbor - if (storage->sample_count < ETX_ACCELERATED_INTERVAL) { - return false; - } + return false; } - //tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks); + if (time_update == 0) { + return true; + } - 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) { diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.h b/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.h index 55c125456d1..c785cc5c983 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.h +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/etx/etx.h @@ -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_ */ diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss.c index 511c07aa985..ae960bc8d07 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss.c +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss.c @@ -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) { diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.c index d2826ca7e85..0d9dc7c505b 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.c +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.h b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.h index 35e1d0cc461..4d10667924a 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.h +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_common.h @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_test_api.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_test_api.c new file mode 100644 index 00000000000..7b1e696ea04 --- /dev/null +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_test_api.c @@ -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 + +#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; +} diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c index 452c6e177bf..d5272250f83 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c @@ -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); diff --git a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h index 917b599878f..c3d31fa67ef 100644 --- a/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h +++ b/features/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h @@ -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_*/ diff --git a/features/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c b/features/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c index 8e321a9468f..47c09ec5e26 100644 --- a/features/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c +++ b/features/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c @@ -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) diff --git a/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c b/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c index 2f19eb70a4e..f3c0ccba8c6 100644 --- a/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c +++ b/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c @@ -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; + } + } + + 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; + } } - serverInfo->clientIdSequence++; + //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,26 +345,52 @@ 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); - } else { - entry->lifetime = 0xffffffff; - entry->preferredLifetime = 0xffffffff; - } + if (validLifetime != 0xffffffff) { + entry->lifetime = validLifetime; + entry->preferredLifetime = (validLifetime >> 1); + } else { + 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) +{ + 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) { - ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { - if (memcmp(cur->nonTemporalAddress, address, 16) == 0) { - return cur; + 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) +{ + 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_alloacted_address_entry_t *newEntry = NULL; + 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 (newEntry) { - 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); + 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; + 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); } } } diff --git a/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h b/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h index ba17b340f5d..3b4c0643e2e 100644 --- a/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h +++ b/features/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h @@ -28,29 +28,36 @@ #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 { - uint8_t nonTemporalAddress[16]; +typedef struct dhcpv6_allocated_address_entry_s { uint8_t linkId[8]; /*!< Services UL64 */ - uint16_t linkType; 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_alloacted_address_entry_t; +} dhcpv6_allocated_address_entry_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 struct dhcpv6_allocated_address_s { + uint8_t nonTemporalAddress[16]; + uint8_t linkId[8]; /*!< Services UL64 */ + uint16_t linkType; + uint32_t iaID; + uint32_t T0; + uint32_t T1; + uint32_t preferredLifetime; + uint32_t lifetime; +} dhcpv6_allocated_address_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 diff --git a/features/nanostack/sal-stack-nanostack/source/libNET/src/net_6lowpan_parameter_api.c b/features/nanostack/sal-stack-nanostack/source/libNET/src/net_6lowpan_parameter_api.c index 59bea2198aa..cd1649df3c8 100644 --- a/features/nanostack/sal-stack-nanostack/source/libNET/src/net_6lowpan_parameter_api.c +++ b/features/nanostack/sal-stack-nanostack/source/libNET/src/net_6lowpan_parameter_api.c @@ -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 } diff --git a/features/nanostack/sal-stack-nanostack/source/libNET/src/net_load_balance.c b/features/nanostack/sal-stack-nanostack/source/libNET/src/net_load_balance.c index 90f4960dffd..a643d90fde3 100644 --- a/features/nanostack/sal-stack-nanostack/source/libNET/src/net_load_balance.c +++ b/features/nanostack/sal-stack-nanostack/source/libNET/src/net_load_balance.c @@ -146,12 +146,14 @@ 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 } -int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval) +int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval) { #ifdef HAVE_6LOWPAN_ND protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id); @@ -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 } diff --git a/features/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c b/features/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c index 5ee8a60dc66..e369f6c3758 100644 --- a/features/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c +++ b/features/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c @@ -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 } @@ -895,7 +899,7 @@ int8_t arm_pana_client_key_pull(int8_t interface_id) return pana_client_key_pull(interface_id); } -int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info) +int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || thread_info(cur) || !cur->mac_parameters || (cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED) == 0) { @@ -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) { diff --git a/features/nanostack/sal-stack-nanostack/source/libNET/src/socket_api.c b/features/nanostack/sal-stack-nanostack/source/libNET/src/socket_api.c index 65b192145dd..2cf27829c5e 100644 --- a/features/nanostack/sal-stack-nanostack/source/libNET/src/socket_api.c +++ b/features/nanostack/sal-stack-nanostack/source/libNET/src/socket_api.c @@ -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; diff --git a/features/nanostack/sal-stack-nanostack/sources.mk b/features/nanostack/sal-stack-nanostack/sources.mk index 1cc99981bd2..840c51105d3 100644 --- a/features/nanostack/sal-stack-nanostack/sources.mk +++ b/features/nanostack/sal-stack-nanostack/sources.mk @@ -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 \