diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp index 149395490ea..6ad87de0370 100644 --- a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp @@ -619,7 +619,7 @@ static void rf_handle_cca_ed_done(void) backup_time = 0; } rf_backup_timer_start(0, backup_time + PACKET_PROCESSING_TIME); - device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL_RX, 0, 0); return; } if ((cca_enabled == true) && (((int8_t) rf_read_rf_register(RF_EDV, rf_module) > cca_threshold))) { @@ -997,7 +997,7 @@ static void rf_backup_timer_interrupt(void) } if ((rf_state == RF_CSMA_STARTED) || (rf_state == RF_CSMA_WHILE_RX)) { TEST_CSMA_DONE - device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL_RX, 0, 0); } TEST_TX_DONE TEST_RX_DONE diff --git a/connectivity/drivers/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp b/connectivity/drivers/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp index 13f591de47a..4c613404fbd 100644 --- a/connectivity/drivers/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp +++ b/connectivity/drivers/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp @@ -848,7 +848,11 @@ static void rf_cca_timer_interrupt(void) rf_flush_tx_fifo(); tx_finnish_time = rf_get_timestamp(); 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); + if (rf_state == RF_RX_STARTED) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL_RX, 0, 0); + } else { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + } } } else { if (status == PHY_RESTART_CSMA) { @@ -1143,7 +1147,7 @@ static void rf_irq_task_process_irq(void) 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); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL_RX, 1, 0); rf_send_command(S2LP_CMD_SABORT); rf_poll_state_change(S2LP_STATE_READY); rf_send_command(S2LP_CMD_FLUSHTXFIFO); diff --git a/connectivity/libraries/nanostack-libservice/mbed-client-libservice/ns_nvm_helper.h b/connectivity/libraries/nanostack-libservice/mbed-client-libservice/ns_nvm_helper.h index b59c9b29efd..aea476a0af3 100644 --- a/connectivity/libraries/nanostack-libservice/mbed-client-libservice/ns_nvm_helper.h +++ b/connectivity/libraries/nanostack-libservice/mbed-client-libservice/ns_nvm_helper.h @@ -1,20 +1,18 @@ -// ---------------------------------------------------------------------------- -// Copyright 2016-2017 ARM Ltd. -// -// 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. -// ---------------------------------------------------------------------------- +/* + * Copyright (c) 2016-2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * NanoStack NVM helper functions to read, write and delete key-value pairs to platform NVM. diff --git a/connectivity/libraries/nanostack-libservice/source/nvmHelper/ns_nvm_helper.c b/connectivity/libraries/nanostack-libservice/source/nvmHelper/ns_nvm_helper.c index af07e05bf4c..eea820951ec 100644 --- a/connectivity/libraries/nanostack-libservice/source/nvmHelper/ns_nvm_helper.c +++ b/connectivity/libraries/nanostack-libservice/source/nvmHelper/ns_nvm_helper.c @@ -1,20 +1,18 @@ -// ---------------------------------------------------------------------------- -// Copyright 2016-2017 ARM Ltd. -// -// 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. -// ---------------------------------------------------------------------------- +/* + * Copyright (c) 2016-2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h index 1a3be195aa1..88a51504587 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h @@ -142,6 +142,15 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty */ void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address); +/** +* \brief Enable DHCPv6 Relay Agent to add interface ID option to relay frame. Default is disabled. +* +* +* \param instance The instance ID of the registered server. +* \param enable true add interface option +*/ +void dhcp_service_relay_interface_id_option_enable(uint16_t instance, bool enable); + /** * \brief Get DHCPv6 Relay Agent address pointer. * diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_api.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_api.h index be5a90c1d21..e6aa23270e4 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_api.h @@ -49,6 +49,7 @@ typedef struct fhss_callback fhss_callback_t; typedef enum { FHSS_UNSYNCHRONIZED, FHSS_SYNCHRONIZED, + FHSS_EXPEDITED_FORWARDING } fhss_states; /** diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_ws_extension.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_ws_extension.h index ac2e1b446f7..d98b5ace978 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_ws_extension.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/fhss_ws_extension.h @@ -118,6 +118,27 @@ extern int ns_fhss_set_neighbor_info_fp(const fhss_api_t *fhss_api, fhss_get_nei */ extern int ns_fhss_ws_set_hop_count(const fhss_api_t *fhss_api, const uint8_t hop_count); +/** + * @brief WS TX allowance levels. + */ +typedef enum { + /** Allow transmitting only on TX slots. */ + WS_TX_SLOT, + /** Allow transmitting only on TX and RX slots. */ + WS_TX_AND_RX_SLOT, + /** Allow transmitting always. Also unicast on broadcast channel. */ + WS_TX_ALWAYS +} fhss_ws_tx_allow_level; + +/** + * @brief Set node unicast TX allowance level. Allows device to use the unicast and broadcast channel for unicast transmission as described by fhss_ws_tx_allow_level. + * @param fhss_api FHSS instance. + * @param global_level Level of TX allowance in normal mode. + * @param ef_level Level of TX allowance in expedited forwarding mode. + * @return 0 on success, -1 on fail. + */ +extern int ns_fhss_ws_set_tx_allowance_level(const fhss_api_t *fhss_api, const fhss_ws_tx_allow_level global_level, const fhss_ws_tx_allow_level ef_level); + #ifdef __cplusplus } #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_api.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_api.h index 8e545987eab..bc5b13fcef5 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_api.h @@ -128,10 +128,11 @@ typedef void mcps_data_request(const mac_api_t *api, const mcps_data_req_t *data * @param data MCPS-DATA.request specific values * @param ie_ext Information element list to MCPS-DATA.request * @param asynch_channel_list Optional channel list to asynch data request. Give NULL when normal data request. + * @param priority Data request priority level * * Asynch data request is mac standard extension. asynch_channel_list include channel mask which channel message is requested to send. */ -typedef void mcps_data_request_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const struct channel_list_s *asynch_channel_list); +typedef void mcps_data_request_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const struct channel_list_s *asynch_channel_list, mac_data_priority_t priority); /** * @brief mcps_purge_request MCPS_PURGE request call diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_mcps.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_mcps.h index 614a01e326c..8e99c2f4319 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_mcps.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/mac_mcps.h @@ -192,5 +192,17 @@ typedef struct mcps_edfe_response_s { bool use_message_handle_to_discover: 1; /**< EDFE Data request message ID is valid at message_handle. */ } mcps_edfe_response_t; +/** + * @brief enum mac_data_priority_t Data request priority level + * + * Data request priority level may affect CCA process and MAC queue process + */ +typedef enum mac_data_priority_e { + MAC_DATA_NORMAL_PRIORITY = 0, /**< Normal MCPS DATA REQ */ + MAC_DATA_MEDIUM_PRIORITY = 1, /**< Indirect Data which is polled */ + MAC_DATA_HIGH_PRIORITY = 2, /**< MAC command usually use this and beacon */ + MAC_DATA_EXPEDITE_FORWARD = 3 /**< Expedite forward level give highest priority */ +} mac_data_priority_t; + #endif // MAC_MCPS_H diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h index 859457d1611..992046dfdea 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h @@ -264,6 +264,7 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /*=0 Success with amount of entries written in table. + * \return >=0 if neighbor_ptr is NULL returns the amount of neighbors currently. + * \return <0 Failure. + */ +int ws_neighbor_info_get( + int8_t interface_id, + ws_neighbour_info_t *neighbor_ptr, + uint16_t count); + /** * Set minimum RF sensitivity acceptable for the parent selection * diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c index a8279994eb3..6c6a0ca4453 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c @@ -83,7 +83,10 @@ #define TRACE_GROUP "6lo" /* Data rate for application used in Stagger calculation */ -#define STAGGER_DATARATE_FOR_APPL(n) ((n)*25/100) +#define STAGGER_DATARATE_FOR_APPL(n) ((n)*75/100) + +/* Time after network is considered stable and smaller stagger values can be given*/ +#define STAGGER_STABLE_NETWORK_TIME 3600*4 #ifdef HAVE_RPL rpl_domain_t *protocol_6lowpan_rpl_domain; @@ -839,7 +842,7 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am datarate = 250000; } else if (ws_info(cur_interface)) { network_size = ws_common_network_size_estimate_get(cur_interface); - datarate = ws_common_datarate_get(cur_interface); + datarate = ws_common_usable_application_datarate_get(cur_interface); } else { // 6LoWPAN ND network_size = 1000; @@ -850,11 +853,23 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am // If no data amount given, use 1kB data_amount = 1; } + if (datarate < 25000) { + // Minimum data rate used in calculations is 25kbs to prevent invalid values + datarate = 25000; + } /* * Do not occupy whole bandwidth, leave space for network formation etc... */ - datarate = STAGGER_DATARATE_FOR_APPL(datarate); + if (ws_info(cur_interface) && + (ws_common_connected_time_get(cur_interface) > STAGGER_STABLE_NETWORK_TIME || ws_common_authentication_time_get(cur_interface) == 0)) { + // After four hours of network connected full bandwidth is given to application + // Authentication has not been required during bootstrap so network load is much smaller + } else { + // Smaller data rate allowed as we have just joined to the network and Authentication was made + datarate = STAGGER_DATARATE_FOR_APPL(datarate); + } + stagger_value = 1 + ((data_amount * 1024 * 8 * network_size) / datarate); /** * Example: diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index 0a21788cc26..11a2a8d989f 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -2184,7 +2184,7 @@ void nwk_6lowpan_nd_address_registartion_ready(protocol_interface_info_entry_t * // arm_nwk_6lowpan_rpl_dodag_poison from a previous connection may have left force_leaf set rpl_control_force_leaf(protocol_6lowpan_rpl_domain, false); rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, true); - rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, NULL, NULL, cur); + rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, NULL, NULL, NULL, cur); } // Send unicast DIS to coordinator nwk_bootstrap_icmp_rpl_dis_coord_msg_tx(cur); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c index 86fc64ebde5..73d6690f972 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c @@ -964,6 +964,62 @@ int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_ return 0; } +int8_t mac_helper_mac_mlme_max_csma_backoffs_set(int8_t interface_id, uint8_t csma_backoffs) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + + if (!cur || !cur->mac_api) { + return -1; + } + mlme_set_t set_req; + set_req.attr = macMaxCSMABackoffs; + set_req.attr_index = 0; + set_req.value_pointer = &csma_backoffs; + set_req.value_size = 1; + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + + return 0; +} + +int8_t mac_helper_mac_mlme_be_set(int8_t interface_id, uint8_t min_be, uint8_t max_be) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + + if (!cur || !cur->mac_api) { + return -1; + } + mlme_set_t set_req; + set_req.attr = macMinBE; + set_req.attr_index = 0; + set_req.value_pointer = &min_be; + set_req.value_size = 1; + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + + set_req.attr = macMaxBE; + set_req.attr_index = 0; + set_req.value_pointer = &max_be; + set_req.value_size = 1; + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + + return 0; +} + +int8_t mac_helper_mac_mlme_data_request_restart_set(int8_t interface_id, mlme_request_restart_config_t *request_restart_config) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + + if (!cur || !cur->mac_api) { + return -1; + } + mlme_set_t set_req; + set_req.attr = macRequestRestart; + set_req.attr_index = 0; + set_req.value_pointer = (void *)request_restart_config; + set_req.value_size = sizeof(mlme_request_restart_config_t); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + + return 0; +} int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id) { diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h index fd1eb19d868..f85916bcf78 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h @@ -130,6 +130,12 @@ void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_dev int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set); +int8_t mac_helper_mac_mlme_max_csma_backoffs_set(int8_t interface_id, uint8_t csma_backoffs); + +int8_t mac_helper_mac_mlme_be_set(int8_t interface_id, uint8_t min_be, uint8_t max_be); + +int8_t mac_helper_mac_mlme_data_request_restart_set(int8_t interface_id, mlme_request_restart_config_t *request_restart_config); + int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id); int8_t mac_helper_start_auto_cca_threshold(int8_t interface_id, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mpx_api.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mpx_api.h index e4c2ee64076..b210e4a3954 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mpx_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mpx_api.h @@ -17,7 +17,7 @@ #ifndef MPX_API_H_ #define MPX_API_H_ - +#include "mac_mcps.h" struct mcps_data_req_s; struct mcps_data_conf_s; struct mcps_data_ind_s; @@ -30,9 +30,10 @@ typedef struct mpx_api_s mpx_api_t; * @param api API to handle the request * @param data MCPS-DATA.request specific values * @param user_id MPX user ID + * @param priority priority level * */ -typedef void mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id); +typedef void mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id, mac_data_priority_t priority); /** * @brief mpx_data_queue_clean clean MPX user data @@ -82,6 +83,22 @@ typedef uint16_t mpx_header_size_get(const mpx_api_t *api, uint16_t user_id); */ typedef int8_t mpx_data_cb_register(const mpx_api_t *api, mpx_data_confirm *confirm_cb, mpx_data_indication *indication_cb, uint16_t user_id); +/** + * @brief mpx_eui64_purge_request Purge EUI-64 related data from MPX + * @param api The API which handled the response + * @param eui64 EUI-64 to purge + * + */ +typedef void mpx_eui64_purge_request(const mpx_api_t *api, const uint8_t *eui64); + +/** + * \brief mpx_high_priority_mode_set Enable/Disable MPX high priority mode for TX process + * @param api The API which handled the response + * @param enable_mode True for enable High Priority mode, False disable + * + */ +typedef void mpx_high_priority_mode_set(const mpx_api_t *api, bool enable_mode); + /** * \brief Struct mpx_api_s defines functions for MPX user for register call backs and send data. */ @@ -90,6 +107,8 @@ struct mpx_api_s { mpx_data_purge_request *mpx_data_purge; /**< MPX data Purge. */ mpx_header_size_get *mpx_headroom_size_get; /**< MPX headroom size get in bytes. */ mpx_data_cb_register *mpx_user_registration; /**< MPX User cb registration must be call before enable to send or RX data*/ + mpx_eui64_purge_request *mpx_eui64_purge; /**< MPX Purge EUI-64 related data */ + mpx_high_priority_mode_set *mpx_priority_mode_set; /**< MPX request to enable / disable High Priority mode */ }; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c index 7409f53a907..2a35d85dfeb 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c +++ b/connectivity/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, false); + return DHCPv6_server_service_set_address_generation_anonymous(interface_id, prefix_ptr, anonymous, false); #else (void) interface_id; (void) prefix_ptr; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c index bc137b1a9f0..79a39724251 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_test_api.c @@ -70,7 +70,7 @@ int_fast8_t arm_nwk_6lowpan_thread_test_add_neighbour( const uint8_t *id_mask, const uint8_t *route_data) { -#ifdef HAVE_THREAD +#ifdef HAVE_THREAD_ROUTER protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { @@ -94,7 +94,7 @@ int_fast8_t arm_nwk_6lowpan_thread_test_remove_neighbour( int8_t interface_id, uint16_t neighbour_short_addr) { -#ifdef HAVE_THREAD +#ifdef HAVE_THREAD_ROUTER protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { @@ -1220,7 +1220,7 @@ int8_t thread_test_initial_slaac_iid_set(int8_t interface_id, uint8_t *iid) int8_t thread_test_router_id_request_send(int8_t interface_id, uint8_t status) { -#ifdef HAVE_THREAD +#ifdef HAVE_THREAD_ROUTER protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c index 74d783c8e6f..0374731751f 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/adaptation_interface.c @@ -101,6 +101,7 @@ typedef struct { uint16_t indirect_big_packet_threshold; uint16_t max_indirect_big_packets_total; uint16_t max_indirect_small_packets_per_child; + uint32_t last_rx_high_priority; bool fragmenter_active; /*!< Fragmenter state */ adaptation_etx_update_cb *etx_update_cb; mpx_api_t *mpx_api; @@ -109,6 +110,7 @@ typedef struct { } fragmenter_interface_t; #define LOWPAN_ACTIVE_UNICAST_ONGOING_MAX 10 +#define LOWPAN_HIGH_PRIORITY_STATE_LENGTH 50 //5 seconds 100us ticks /* Minimum buffer amount and memory size to ensure operation even in out of memory situation */ @@ -116,6 +118,7 @@ typedef struct { #define LOWPAN_MEM_LIMIT_MIN_MEMORY 10000 #define LOWPAN_MEM_LIMIT_REMOVE_NORMAL 3000 // Remove when approaching memory limit #define LOWPAN_MEM_LIMIT_REMOVE_MAX 10000 // Remove when at memory limit +#define LOWPAN_MEM_LIMIT_REMOVE_EF_MODE 20000 // Remove when out of memory and we are in EF mode @@ -155,6 +158,7 @@ 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 bool lowpan_adaptation_purge_from_mac(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, uint8_t msduhandle); static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm) { @@ -251,6 +255,28 @@ 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 void lowpan_adaptation_tx_queue_write_to_front(fragmenter_interface_t *interface_ptr, buffer_t *buf) +{ + buffer_t *lower_priority_buf = NULL; + + ns_list_foreach(buffer_t, cur, &interface_ptr->directTxQueue) { + + if (cur->priority <= buf->priority) { + lower_priority_buf = cur; + break; + } + } + + if (lower_priority_buf) { + ns_list_add_before(&interface_ptr->directTxQueue, lower_priority_buf, buf); + } else { + ns_list_add_to_end(&interface_ptr->directTxQueue, buf); + } + interface_ptr->directTxQueue_size++; + lowpan_adaptation_tx_queue_level_update(interface_ptr); + protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size); +} + 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. @@ -258,6 +284,12 @@ static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interfa return NULL; } ns_list_foreach_safe(buffer_t, buf, &interface_ptr->directTxQueue) { + + if (buf->link_specific.ieee802_15_4.requestAck && interface_ptr->last_rx_high_priority && buf->priority < QOS_EXPEDITE_FORWARD) { + //Stop reading at this point when Priority is not enough big + return NULL; + } + if (lowpan_buffer_tx_allowed(interface_ptr, buf)) { ns_list_remove(&interface_ptr->directTxQueue, buf); interface_ptr->directTxQueue_size--; @@ -460,6 +492,7 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id) buffer_free_list(&interface_ptr->directTxQueue); interface_ptr->directTxQueue_size = 0; interface_ptr->directTxQueue_level = 0; + interface_ptr->last_rx_high_priority = 0; return 0; } @@ -506,12 +539,30 @@ void lowpan_adaptation_free_heap(bool full_gc) { ns_list_foreach(fragmenter_interface_t, interface_ptr, &fragmenter_interface_list) { // Go through all interfaces and free small amount of memory - // This is not very radical, but gives time to recover wthout causing too harsh changes - lowpan_adaptation_free_low_priority_packets(interface_ptr->interface_id, full_gc ? LOWPAN_MEM_LIMIT_REMOVE_MAX : LOWPAN_MEM_LIMIT_REMOVE_NORMAL); + // This is not very radical, but gives time to recover without causing too harsh changes + buffer_priority_t priority = QOS_NORMAL; + uint32_t amount = LOWPAN_MEM_LIMIT_REMOVE_NORMAL; + + if (full_gc && interface_ptr->last_rx_high_priority) { + // We have encountered out of memory in EF state We handle this as Critical state + // Large amount of memory is freed and packets lower than EF priority can be dropped + priority = QOS_NETWORK_CTRL; + amount = LOWPAN_MEM_LIMIT_REMOVE_EF_MODE; + } else if (interface_ptr->last_rx_high_priority) { + // We are running out of memory and we are in EF state. We handle this as severe state + // Some amount of memory is freed and also lower than EF priority packets are dropped + priority = QOS_NETWORK_CTRL; + amount = LOWPAN_MEM_LIMIT_REMOVE_MAX; + } else if (full_gc) { + // We have encountered out of memory. we need to remove more packets, but we only remove normal priority packets + amount = LOWPAN_MEM_LIMIT_REMOVE_MAX; + } + + lowpan_adaptation_free_low_priority_packets(interface_ptr->interface_id, priority, amount); } } -int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, uint32_t requested_amount) +int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, buffer_priority_t max_priority, uint32_t requested_amount) { fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id); @@ -543,7 +594,7 @@ int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, uint32_t //Only remove last entries from TX queue with low priority ns_list_foreach_reverse_safe(buffer_t, entry, &interface_ptr->directTxQueue) { - if (entry->priority == QOS_NORMAL) { + if (entry->priority <= max_priority) { memory_freed += sizeof(buffer_t) + entry->size; packets_freed++; ns_list_remove(&interface_ptr->directTxQueue, entry); @@ -1028,12 +1079,34 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf buf->link_specific.ieee802_15_4.rf_channel_switch = false; } } + //Define data priority + mac_data_priority_t data_priority; + + switch (buf->priority) { + case QOS_HIGH: + data_priority = MAC_DATA_MEDIUM_PRIORITY; + break; + case QOS_NETWORK_CTRL: + data_priority = MAC_DATA_HIGH_PRIORITY; + break; + case QOS_EXPEDITE_FORWARD: + data_priority = MAC_DATA_EXPEDITE_FORWARD; + break; + case QOS_MAC_BEACON: + data_priority = MAC_DATA_HIGH_PRIORITY; + break; + default: + data_priority = MAC_DATA_NORMAL_PRIORITY; + break; + } if (interface_ptr->mpx_api) { dataReq.ExtendedFrameExchange = buf->options.edfe_mode; - interface_ptr->mpx_api->mpx_data_request(interface_ptr->mpx_api, &dataReq, interface_ptr->mpx_user_id); + interface_ptr->mpx_api->mpx_data_request(interface_ptr->mpx_api, &dataReq, interface_ptr->mpx_user_id, data_priority); } else { - cur->mac_api->mcps_data_req(cur->mac_api, &dataReq); + mcps_data_req_ie_list_t ie_list; + memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t)); + cur->mac_api->mcps_data_req_ext(cur->mac_api, &dataReq, &ie_list, NULL, data_priority); } } @@ -1075,9 +1148,119 @@ static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buff if (is_unicast && lowpan_adaptation_is_destination_tx_active(&interface_ptr->activeUnicastList, buf)) { return false; } + + if (is_unicast && interface_ptr->last_rx_high_priority && buf->priority < QOS_EXPEDITE_FORWARD) { + return false; + } return true; } +static uint32_t lowpan_adaptation_time_stamp_diff(uint32_t compare_stamp) +{ + if (protocol_core_monotonic_time < compare_stamp) { + return compare_stamp - protocol_core_monotonic_time; + } + return protocol_core_monotonic_time - compare_stamp; +} + +static bool lowpan_adaptation_high_priority_state_exit(fragmenter_interface_t *interface_ptr) +{ + if (!interface_ptr->last_rx_high_priority || lowpan_adaptation_time_stamp_diff(interface_ptr->last_rx_high_priority) < LOWPAN_HIGH_PRIORITY_STATE_LENGTH) { + return false; + } + + //Check First buffer_from tx queue + buffer_t *buf = ns_list_get_first(&interface_ptr->directTxQueue); + if (buf && buf->priority == QOS_EXPEDITE_FORWARD) { + //TX queue must not include any + return false; + } + + //Check If we have a Any active TX process still active + ns_list_foreach(fragmenter_tx_entry_t, entry, &interface_ptr->activeUnicastList) { + if (entry->buf->priority == QOS_EXPEDITE_FORWARD) { + return false; + } + } + + //Disable High Priority Mode + if (interface_ptr->mpx_api) { + interface_ptr->mpx_api->mpx_priority_mode_set(interface_ptr->mpx_api, false); + } + interface_ptr->last_rx_high_priority = 0; + return true; +} + +static void lowpan_adaptation_high_priority_state_enable(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr) +{ + + if (!interface_ptr->last_rx_high_priority) { + // MPX enaled stack must inform MPX to priority enable + if (interface_ptr->mpx_api) { + interface_ptr->mpx_api->mpx_priority_mode_set(interface_ptr->mpx_api, true); + } + //Purge Active tx queue's all possible's + if (!interface_ptr->fragmenter_active) { + //Purge Only When Fragmenter is not active + ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, entry, &interface_ptr->activeUnicastList) { + + if (lowpan_adaptation_purge_from_mac(cur, interface_ptr, entry->buf->seq)) { + buffer_t *buf = entry->buf; + ns_list_remove(&interface_ptr->activeUnicastList, entry); + interface_ptr->activeTxList_size--; + ns_dyn_mem_free(entry); + //Add message to tx queue front based on priority. Now same priority at buf is prioritised at order + lowpan_adaptation_tx_queue_write_to_front(interface_ptr, buf); + random_early_detetction_aq_calc(cur->random_early_detection, interface_ptr->directTxQueue_size); + } + } + } + } + + //Store timestamp for indicate last RX High Priority message + interface_ptr->last_rx_high_priority = protocol_core_monotonic_time ? protocol_core_monotonic_time : 1; + +} + + +static void lowpan_adaptation_priority_status_update(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr, buffer_priority_t priority) +{ + if (priority == QOS_EXPEDITE_FORWARD) { + lowpan_adaptation_high_priority_state_enable(cur, interface_ptr); + } else { + //Let check can we disable possible High Priority state + lowpan_adaptation_high_priority_state_exit(interface_ptr); + } +} + +void lowpan_adaptation_expedite_forward_enable(protocol_interface_info_entry_t *cur) +{ + fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id); + if (!interface_ptr) { + return; + } + lowpan_adaptation_high_priority_state_enable(cur, interface_ptr); +} + +void lowpan_adaptation_interface_slow_timer(protocol_interface_info_entry_t *cur) +{ + fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id); + if (!interface_ptr) { + return; + } + + if (lowpan_adaptation_high_priority_state_exit(interface_ptr)) { + //Activate Packets from TX queue + 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); + } + //Update Average QUEUE + random_early_detetction_aq_calc(cur->random_early_detection, interface_ptr->directTxQueue_size); + } +} + int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf) { bool is_room_for_new_message; @@ -1105,6 +1288,8 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff buffer_priority_set(buf, QOS_HIGH); } + //Update priority status + lowpan_adaptation_priority_status_update(cur, interface_ptr, buf->priority); //Check packet size bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr); @@ -1409,6 +1594,8 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c } // When confirmation is for direct transmission, push all allowed buffers to MAC if (active_direct_confirm == true) { + //Check Possibility for exit from High Priority state + lowpan_adaptation_high_priority_state_exit(interface_ptr); buffer_t *buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr); while (buf_from_queue) { lowpan_adaptation_interface_tx(cur, buf_from_queue); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h index 13401df1f0f..5b88e287231 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/lowpan_adaptation_interface.h @@ -38,7 +38,7 @@ int8_t lowpan_adaptation_interface_mpx_register(int8_t interface_id, struct mpx_ void lowpan_adaptation_free_heap(bool full_gc); -int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, uint32_t requested_amount); +int8_t lowpan_adaptation_free_low_priority_packets(int8_t interface_id, buffer_priority_t max_priority, uint32_t requested_amount); /** @@ -62,4 +62,8 @@ int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_in 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); +void lowpan_adaptation_expedite_forward_enable(struct protocol_interface_info_entry *cur); + +void lowpan_adaptation_interface_slow_timer(struct protocol_interface_info_entry *cur); + #endif /* LOWPAN_ADAPTATION_INTERFACE_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c index 75a1178bfc6..1fc5a5940c3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, Arm Limited and affiliates. + * Copyright (c) 2018-2021, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,16 +38,18 @@ #include "RPL/rpl_data.h" #include "Common_Protocols/icmpv6.h" #include "Common_Protocols/icmpv6_radv.h" +#include "Common_Protocols/ip.h" #include "ws_management_api.h" #include "net_rpl.h" #include "Service_Libs/nd_proxy/nd_proxy.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" #include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/lowpan_adaptation_interface.h" #include "DHCPv6_Server/DHCPv6_server_service.h" #include "DHCPv6_client/dhcpv6_client_api.h" #include "libDHCPv6/libDHCPv6_vendordata.h" #include "libNET/src/net_dns_internal.h" - +#include "platform/os_whiteboard.h" #include "ws_bbr_api.h" @@ -197,7 +199,7 @@ static void ws_bbr_rpl_version_increase(protocol_interface_info_entry_t *cur) 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) +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, uint32_t lifetime) { if (imin == 0 || doubling == 0) { // use default values @@ -205,12 +207,33 @@ void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8 doubling = WS_RPL_DIO_DOUBLING_SMALL; redundancy = WS_RPL_DIO_REDUNDANCY_SMALL; } + uint8_t lifetime_unit = 60; + uint8_t default_lifetime; + + if (lifetime == 0) { + // 2 hours default lifetime + lifetime = 120 * 60; + } else if (lifetime <= 250 * 60) { + // Lifetime unit of 60 is ok up to 4 hours + } else if (lifetime <= 250 * 120) { + //more than 4 hours needs larger lifetime unit + lifetime_unit = 120; + } else if (lifetime <= 250 * 240) { + lifetime_unit = 240; + } else { + // Maximum lifetime is 16 hours 40 minutes + lifetime = 250 * 240; + lifetime_unit = 240; + } + default_lifetime = lifetime / lifetime_unit; if (rpl_conf.dio_interval_min == imin && rpl_conf.dio_interval_doublings == doubling && rpl_conf.dio_redundancy_constant == redundancy && rpl_conf.dag_max_rank_increase == dag_max_rank_increase && - rpl_conf.min_hop_rank_increase == min_hop_rank_increase) { + rpl_conf.min_hop_rank_increase == min_hop_rank_increase && + rpl_conf.default_lifetime == default_lifetime && + rpl_conf.lifetime_unit == lifetime_unit) { // Same values no update needed return; } @@ -220,6 +243,8 @@ void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8 rpl_conf.dio_redundancy_constant = redundancy; rpl_conf.dag_max_rank_increase = dag_max_rank_increase; rpl_conf.min_hop_rank_increase = min_hop_rank_increase; + rpl_conf.default_lifetime = default_lifetime; + rpl_conf.lifetime_unit = lifetime_unit; if (protocol_6lowpan_rpl_root_dodag) { rpl_control_update_dodag_config(protocol_6lowpan_rpl_root_dodag, &rpl_conf); @@ -343,30 +368,11 @@ static void ws_bbr_slaac_remove(protocol_interface_info_entry_t *cur, uint8_t *u addr_policy_table_delete_entry(ula_prefix, 64); } - -static int ws_bbr_static_dodagid_create(protocol_interface_info_entry_t *cur) -{ - if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 16) != 0) { - // address generated - return 0; - } - // This address is only used if no other address available. - if_address_entry_t *add_entry = ws_bbr_slaac_generate(cur, static_dodag_id_prefix); - if (!add_entry) { - tr_err("dodagid create failed"); - return -1; - } - memcpy(current_dodag_id, add_entry->address, 16); - tr_info("BBR generate DODAGID %s", trace_ipv6(current_dodag_id)); - - return 0; -} - /* * 0 static non rooted self generated own address * 1 static address with backbone connectivity */ -static void ws_bbr_bb_static_prefix_get(uint8_t *dodag_id_ptr) +static uint8_t *ws_bbr_bb_static_prefix_get(uint8_t *dodag_id_ptr) { /* Get static ULA prefix if we have configuration in backbone and there is address we use that. @@ -377,14 +383,46 @@ static void ws_bbr_bb_static_prefix_get(uint8_t *dodag_id_ptr) protocol_interface_info_entry_t *bb_interface = protocol_stack_interface_info_get_by_id(backbone_interface_id); if (bb_interface && bb_interface->ipv6_configure->ipv6_stack_mode == NET_IPV6_BOOTSTRAP_STATIC) { - if (protocol_address_prefix_cmp(bb_interface, bb_interface->ipv6_configure->static_prefix64, 64)) { - memcpy(dodag_id_ptr, bb_interface->ipv6_configure->static_prefix64, 8); + ns_list_foreach(if_address_entry_t, addr, &bb_interface->ip_addresses) { + if (bitsequal(addr->address, bb_interface->ipv6_configure->static_prefix64, 64)) { + // static address available in interface copy the prefix and return the address + if (dodag_id_ptr) { + memcpy(dodag_id_ptr, bb_interface->ipv6_configure->static_prefix64, 8); + } + return addr->address; + } } } - return; + return NULL; } +static int ws_bbr_static_dodagid_create(protocol_interface_info_entry_t *cur) +{ + if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 16) != 0) { + // address generated + return 0; + } + + uint8_t *static_address_ptr = ws_bbr_bb_static_prefix_get(NULL); + if (static_address_ptr) { + memcpy(current_dodag_id, static_address_ptr, 16); + tr_info("BBR Static DODAGID %s", trace_ipv6(current_dodag_id)); + return 0; + } + + // This address is only used if no other address available. + if_address_entry_t *add_entry = ws_bbr_slaac_generate(cur, static_dodag_id_prefix); + if (!add_entry) { + tr_err("dodagid create failed"); + return -1; + } + memcpy(current_dodag_id, add_entry->address, 16); + tr_info("BBR generate DODAGID %s", trace_ipv6(current_dodag_id)); + + return 0; +} + static void ws_bbr_dodag_get(uint8_t *local_prefix_ptr, uint8_t *global_prefix_ptr) { uint8_t global_address[16]; @@ -414,6 +452,7 @@ static void ws_bbr_dodag_get(uint8_t *local_prefix_ptr, uint8_t *global_prefix_p memcpy(global_prefix_ptr, global_address, 8); return; } + static void wisun_bbr_na_send(int8_t interface_id, const uint8_t target[static 16]) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); @@ -425,6 +464,8 @@ static void wisun_bbr_na_send(int8_t interface_id, const uint8_t target[static 1 return; } + whiteboard_os_modify(target, ADD); + buffer_t *buffer = icmpv6_build_na(cur, false, true, true, target, NULL, ADDR_UNSPECIFIED); protocol_push(buffer); return; @@ -478,7 +519,6 @@ static void ws_bbr_dhcp_server_dns_info_update(protocol_interface_info_entry_t * for (int n = 0; n < MAX_DNS_RESOLUTIONS; n++) { if (pre_resolved_dns_queries[n].domain_name != NULL) { ptr = net_dns_option_vendor_option_data_dns_query_write(ptr, pre_resolved_dns_queries[n].address, pre_resolved_dns_queries[n].domain_name); - tr_info("set DNS query result for %s, addr: %s", pre_resolved_dns_queries[n].domain_name, tr_ipv6(pre_resolved_dns_queries[n].address)); } } } @@ -486,6 +526,15 @@ static void ws_bbr_dhcp_server_dns_info_update(protocol_interface_info_entry_t * DHCPv6_server_service_set_vendor_data(cur->id, global_id, ARM_ENTERPRISE_NUMBER, dhcp_vendor_data_ptr, dhcp_vendor_data_len); } +static void wisun_dhcp_address_remove_cb(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info) +{ + (void) interfaceId; + (void) prefix_info; + if (targetAddress) { + whiteboard_os_modify(targetAddress, REMOVE); + } +} + static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id, uint32_t dhcp_address_lifetime) { uint8_t ll[16]; @@ -499,9 +548,11 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 tr_error("DHCPv6 Server create fail"); return; } - DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb); - //Enable SLAAC mode to border router - DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false); + DHCPv6_server_service_callback_set(cur->id, global_id, wisun_dhcp_address_remove_cb, wisun_dhcp_address_add_cb); + //Check for anonymous mode + bool anonymous = (configuration & BBR_DHCP_ANONYMOUS) ? true : false; + + DHCPv6_server_service_set_address_generation_anonymous(cur->id, global_id, anonymous, false); DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, 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); @@ -510,6 +561,7 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 ws_dhcp_client_address_request(cur, global_id, ll); } + static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id) { if (!cur) { @@ -626,9 +678,16 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) */ if ((configuration & BBR_ULA_C) == 0 && memcmp(global_prefix, ADDR_UNSPECIFIED, 8) == 0) { //Global prefix not available count if backup ULA should be created + uint32_t prefix_wait_time = BBR_BACKUP_ULA_DELAY; global_prefix_unavailable_timer += BBR_CHECK_INTERVAL; - tr_debug("Check for backup prefix %"PRIu32"", global_prefix_unavailable_timer); - if (global_prefix_unavailable_timer >= BBR_BACKUP_ULA_DELAY) { + + if (NULL != ws_bbr_bb_static_prefix_get(NULL)) { + // If we have a static configuration we activate it faster. + prefix_wait_time = 40; + } + + tr_debug("Check for backup prefix %"PRIu32" / %"PRIu32"", prefix_wait_time, global_prefix_unavailable_timer); + if (global_prefix_unavailable_timer >= prefix_wait_time) { if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) == 0) { tr_info("start using backup prefix %s", trace_ipv6_prefix(local_prefix, 64)); } @@ -850,6 +909,18 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur) return true; } +static void ws_bbr_forwarding_cb(protocol_interface_info_entry_t *interface, buffer_t *buf) +{ + uint8_t traffic_class = buf->options.traffic_class >> IP_TCLASS_DSCP_SHIFT; + + if (traffic_class == IP_DSCP_EF) { + //indicate EF forwarding to adaptation + lowpan_adaptation_expedite_forward_enable(interface); + } +} + + + void ws_bbr_init(protocol_interface_info_entry_t *interface) { (void) interface; @@ -862,6 +933,7 @@ void ws_bbr_init(protocol_interface_info_entry_t *interface) ws_bbr_fhss_bsi = ws_bbr_bsi_read(&bbr_info_nvm_tlv); tr_debug("Read BSI %u from NVM", ws_bbr_fhss_bsi); } + interface->if_common_forwarding_out_cb = &ws_bbr_forwarding_cb; } @@ -1401,6 +1473,7 @@ int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], if (address) { // Update address memcpy(pre_resolved_dns_queries[n].address, address, 16); + tr_info("Update DNS query result for %s, addr: %s", pre_resolved_dns_queries[n].domain_name, tr_ipv6(pre_resolved_dns_queries[n].address)); } else { // delete entry memset(pre_resolved_dns_queries[n].address, 0, 16); @@ -1423,6 +1496,7 @@ int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], } memcpy(pre_resolved_dns_queries[n].address, address, 16); strcpy(pre_resolved_dns_queries[n].domain_name, domain_name_ptr); + tr_info("set DNS query result for %s, addr: %s", pre_resolved_dns_queries[n].domain_name, tr_ipv6(pre_resolved_dns_queries[n].address)); goto update_information; } } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h index 78892b9f1da..24779fdc220 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -29,7 +29,7 @@ void ws_bbr_pan_version_increase(protocol_interface_info_entry_t *cur); uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur); -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); +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, uint32_t lifetime); void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime); @@ -45,7 +45,7 @@ void ws_bbr_init(protocol_interface_info_entry_t *interface); #define ws_bbr_seconds_timer( cur, seconds) #define ws_bbr_pan_version_increase(cur) #define ws_bbr_pan_size(cur) 0 -#define ws_bbr_rpl_config( cur, 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, lifetime) #define ws_bbr_dhcp_address_lifetime_set(cur, dhcp_address_lifetime) #define ws_bbr_ready_to_start(cur) true #define ws_bbr_backbone_address_get(address) 0 diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c index 7ff5035fb7e..013c3c6e993 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c @@ -28,10 +28,12 @@ #include "mac_common_defines.h" #include "sw_mac.h" #include "ccmLIB.h" +#include "Core/include/ns_monitor.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" #include "ipv6_stack/protocol_ipv6.h" +#include "ipv6_stack/ipv6_routing_table.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/MAC/mac_data_poll.h" #include "6LoWPAN/MAC/mpx_api.h" @@ -103,6 +105,7 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t * static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64); static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id); +static bool ws_bootstrap_eapol_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur); 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); @@ -110,6 +113,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, static void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list); +static void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance); static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur); static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create); @@ -118,6 +122,9 @@ static void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t static void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur); static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur); +static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur); + +static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask); typedef enum { WS_PARENT_SOFT_SYNCH = 0, /**< let FHSS make decision if synchronization is needed*/ @@ -133,15 +140,11 @@ static void ws_bootsrap_create_ll_address(uint8_t *ll_address, const uint8_t *ma ll_address[8] ^= 2; } -mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64) -{ - mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); - if (neighbor) { - return neighbor; - } - neighbor = mac_neighbor_table_entry_allocate(mac_neighbor_info(interface), src64); +static mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_allocate(struct protocol_interface_info_entry *interface, const uint8_t *src64) +{ + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_entry_allocate(mac_neighbor_info(interface), src64); if (!neighbor) { return NULL; } @@ -155,6 +158,17 @@ mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interf return neighbor; } +mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64) + +{ + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); + if (neighbor) { + return neighbor; + } + + return ws_bootstrap_mac_neighbor_allocate(interface, src64); +} + void ws_bootstrap_neighbor_set_stable(struct protocol_interface_info_entry *interface, const uint8_t *src64) { mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); @@ -195,13 +209,13 @@ static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_inf if (!mac_entry) { return; } - ws_bootstrap_neighbor_set_stable(interface, mac_64); mac_entry->lifetime = 0xffffffff; mac_entry->link_lifetime = 0xffffffff; ws_neighbor_class_entry_t *ws_neigh = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index); if (!ws_neigh) { return; } + interface->ws_info->eapol_tx_index = mac_entry->index; } @@ -297,18 +311,25 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } } -static void ws_bootstrap_configure_max_retries(protocol_interface_info_entry_t *cur, uint8_t max_mac_retries, uint8_t max_channel_retries) +static void ws_bootstrap_configure_max_retries(protocol_interface_info_entry_t *cur, uint8_t max_mac_retries) { mac_helper_mac_mlme_max_retry_set(cur->id, max_mac_retries); +} - const fhss_ws_configuration_t *fhss_configuration_cur = ns_fhss_ws_configuration_get(cur->ws_info->fhss_api); - if (fhss_configuration_cur && fhss_configuration_cur->config_parameters.number_of_channel_retries != max_channel_retries) { - fhss_ws_configuration_t fhss_configuration; - memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); - memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); - fhss_configuration.config_parameters.number_of_channel_retries = max_channel_retries; - ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); - } +static void ws_bootstrap_configure_csma_ca_backoffs(protocol_interface_info_entry_t *cur, uint8_t max_backoffs, uint8_t min_be, uint8_t max_be) +{ + mac_helper_mac_mlme_max_csma_backoffs_set(cur->id, max_backoffs); + mac_helper_mac_mlme_be_set(cur->id, min_be, max_be); +} + +static void ws_bootstrap_configure_data_request_restart(protocol_interface_info_entry_t *cur, uint8_t cca_failure_restart_max, uint8_t tx_failure_restart_max, uint16_t blacklist_min_ms, uint16_t blacklist_max_ms) +{ + mlme_request_restart_config_t request_restart_config; + request_restart_config.cca_failure_restart_max = cca_failure_restart_max; + request_restart_config.tx_failure_restart_max = tx_failure_restart_max; + request_restart_config.blacklist_min_ms = blacklist_min_ms; + request_restart_config.blacklist_max_ms = blacklist_max_ms; + mac_helper_mac_mlme_data_request_restart_set(cur->id, &request_restart_config); } static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur) @@ -658,6 +679,8 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) return -1; } ns_sw_mac_fhss_register(cur->mac_api, fhss_api); + // Allow transmitting unicast frames only on TX slots in normal and expedited forwarding mode + ns_fhss_ws_set_tx_allowance_level(fhss_api, WS_TX_SLOT, WS_TX_SLOT); } else { // Read defaults from the configuration to help FHSS testing const fhss_ws_configuration_t *fhss_configuration_copy = ns_fhss_ws_configuration_get(fhss_api); @@ -709,18 +732,33 @@ static int8_t ws_fhss_border_router_configure(protocol_interface_info_entry_t *c //GET BSI from BBR module fhss_configuration.bsi = ws_bbr_bsi_generate(cur); - ws_fhss_set_defaults(cur, &fhss_configuration); ws_fhss_configure_channel_masks(cur, &fhss_configuration); + // Randomize fixed channels. Only used if channel plan is fixed. + cur->ws_info->cfg->fhss.fhss_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + cur->ws_info->cfg->fhss.fhss_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + ws_fhss_set_defaults(cur, &fhss_configuration); ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); return 0; } -static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels) +static bool ws_channel_allowed(uint8_t channel, uint32_t *channel_mask) +{ + if ((1 << (channel % 32)) & (channel_mask[channel / 32])) { + return true; + } + return false; +} + +static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask) { if (configured_fixed_channel == 0xFFFF) { - return randLIB_get_random_in_range(0, number_of_channels - 1); + uint16_t random_channel = randLIB_get_random_in_range(0, number_of_channels - 1); + while (ws_channel_allowed(random_channel, channel_mask) == false) { + random_channel = randLIB_get_random_in_range(0, number_of_channels - 1); + } + return random_channel; } else { return configured_fixed_channel; } @@ -745,8 +783,8 @@ static int8_t ws_fhss_configure(protocol_interface_info_entry_t *cur, bool disco } 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->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); - uint8_t tmp_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); + uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + uint8_t tmp_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel; fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel; ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); @@ -995,7 +1033,8 @@ static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notif break; case DHCPV6_OPTION_DNS_SERVERS: - while (options->option.generic.data_length) { + while (options->option.generic.data_length && options->option.generic.data_length >= 16 && options->option.generic.data_length % 16 == 0) { + // Validate payload to have full 16 byte length addresses without any extra bytes net_dns_server_address_set(interface, server_ll64, options->option.generic.data, server_info->life_time); options->option.generic.data_length -= 16; options->option.generic.data += 16; @@ -1010,6 +1049,30 @@ static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notif } +static void ws_bootstrap_memory_configuration() +{ + /* Configure memory limits for garbage collection based on total memory size + * Starting from these values + * 5% for High mark + * 2% for critical mark + * 1% for Routing limit + * Memory High Critical Drop routing + * 32K RAM 3200 bytes 1280 Bytes 1024 bytes + * 64K RAM 3200 bytes 1280 Bytes 1024 bytes + * 128K RAM 6400 bytes 2560 Bytes 1280 bytes + * 320K RAM 16000 byte 6400 Bytes 3200 bytes + * 640K RAM 32000 byte 12800 Bytes 6400 bytes + * 1000K RAM 50000 bytes 20000 Bytes 10000 bytes + * 4000K RAM 120000 bytes 40000 Bytes 10000 bytes + * */ + // In small memory devices there needs to lower limit so that there some change to be usable + // and there is no use for having very large values on high memory devices + ns_monitor_packet_ingress_rate_limit_by_memory(1024, 10000, 1); + + ns_monitor_heap_gc_threshold_set(3200, 120000, 95, 1280, 40000, 98); + return; +} + static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) { @@ -1066,10 +1129,15 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC); dhcp_client_option_notification_cb_set(cur->id, ws_bootstrap_dhcp_info_notify_cb); - + // Configure memory limits and garbage collection values; + ws_bootstrap_memory_configuration(); ws_nud_table_reset(cur); ws_bootstrap_candidate_table_reset(cur); + // Zero uptime counters + cur->ws_info->uptime = 0; + cur->ws_info->authentication_time = 0; + cur->ws_info->connected_time = 0; blacklist_params_set( WS_BLACKLIST_ENTRY_LIFETIME, @@ -1086,6 +1154,34 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) return ret_val; } +void ws_bootstrap_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type) +{ + if (cur->nwk_bootstrap_state == ER_RPL_NETWORK_LEAVING) { + //Already moved to leaving state. + return; + } + // We are no longer connected + cur->ws_info->connected_time = 0; + + if (cur->rpl_domain && cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + //Stop Asych Timer + ws_bootstrap_asynch_trickle_stop(cur); + tr_debug("Start Network soft leaving"); + if (event_type == WS_FAST_DISCONNECT) { + rpl_control_instant_poison(cur, cur->rpl_domain); + cur->bootsrap_state_machine_cnt = 80; //Give 8 seconds time to send Poison + } else { + rpl_control_poison(cur->rpl_domain, 1); + cur->bootsrap_state_machine_cnt = 6000; //Give 10 minutes time for poison if RPL is not report + } + + } else { + ws_bootstrap_event_discovery_start(cur); + } + cur->nwk_bootstrap_state = ER_RPL_NETWORK_LEAVING; +} + + static void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur) { cur->ws_info->trickle_pas_running = false; @@ -1120,6 +1216,7 @@ static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur) ws_pae_controller_stop(cur); ws_bootstrap_candidate_table_reset(cur); blacklist_clear(); + cur->if_common_forwarding_out_cb = NULL; return nwk_6lowpan_down(cur); } @@ -1564,6 +1661,13 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); } + + if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); + if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_parent_confirm(cur, NULL); + } + } } @@ -1638,7 +1742,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier); cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi; - ws_bootstrap_event_discovery_start(cur); + ws_bootstrap_event_disconnect(cur, WS_NORMAL_DISCONNECT); } return; } @@ -1706,7 +1810,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry // restart PAN version timer //Check Here Do we have a selected Primary parent if (!cur->ws_info->configuration_learned || cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { - cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; + ws_common_border_router_alive_update(cur); } cur->ws_info->pan_information.pan_version = pan_version; @@ -1750,7 +1854,12 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); } - + if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); + if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_parent_confirm(cur, NULL); + } + } /* * A consistent transmission is defined as a PAN Configuration Solicit with @@ -1835,6 +1944,7 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c // Not from long address return; } + ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); //Validate network name switch (message_type) { case WS_FT_PAN_ADVERT: @@ -1851,7 +1961,6 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c default: return; } - ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); //UTT-IE and US-IE are mandatory for all Asynch Messages ws_utt_ie_t ws_utt; if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { @@ -1874,20 +1983,26 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c switch (message_type) { case WS_FT_PAN_ADVERT: // Analyse Advertisement + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PA, 1); tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); ws_bootstrap_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us); break; case WS_FT_PAN_ADVERT_SOL: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PAS, 1); tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); ws_bootstrap_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us); break; case WS_FT_PAN_CONF: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PC, 1); tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); ws_bootstrap_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us); break; - default: + case WS_FT_PAN_CONF_SOL: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PCS, 1); tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); ws_bootstrap_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); + default: + // Unknown message do not process break; } } @@ -1922,6 +2037,13 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent // Enough neighbor entries return; } + uint32_t temp_link_min_timeout; + if (mac_neighbor_info(interface)->neighbour_list_size == mac_neighbor_info(interface)->list_total_size) { + temp_link_min_timeout = 1; //Accept 1 second time from last + } else { + temp_link_min_timeout = interface->ws_info->cfg->timing.temp_link_min_timeout; + } + memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); uint32_t current_time_stamp = ns_sw_mac_read_current_timestamp(interface->mac_api); @@ -1934,17 +2056,14 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent continue; } - if (cur->link_lifetime < WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) { - continue; - } - if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) { //This is our primary parent we cannot delete continue; } - if (cur->nud_active || ws_neighbor->negative_aro_send) { + if (cur->nud_active) { //If NUD process is active do not trig + // or Negative ARO is active continue; } @@ -1953,6 +2072,11 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent continue; } + if (cur->link_lifetime > WS_NEIGHBOUR_TEMPORARY_ENTRY_LIFETIME && cur->link_lifetime <= WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) { + //Do not permit to remove configured temp life time + continue; + } + if (cur->trusted_device) { if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) { @@ -1971,7 +2095,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent //Read current timestamp uint32_t time_from_last_unicast_shedule = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor); - if (time_from_last_unicast_shedule > interface->ws_info->cfg->timing.temp_link_min_timeout) { + if (time_from_last_unicast_shedule >= temp_link_min_timeout) { //Accept only Enough Old Device if (!neighbor_entry_ptr) { //Accept first compare @@ -2020,6 +2144,7 @@ static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_en mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_buffer->neighbor); return false; } + ws_stats_update(interface, STATS_WS_NEIGHBOUR_ADD, 1); return true; } @@ -2035,6 +2160,11 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt //TODO State machine check here + if (ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) { + // Child entry deleted + ws_stats_update(cur, STATS_WS_CHILD_REMOVE, 1); + } + if (entry_ptr->ffd_device) { protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_ptr->mac16); protocol_6lowpan_release_long_link_address_from_neighcache(cur, entry_ptr->mac64); @@ -2044,6 +2174,8 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt ws_nud_entry_remove(cur, entry_ptr); ws_bootstrap_neighbor_delete(cur, entry_ptr); + ws_stats_update(cur, STATS_WS_NEIGHBOUR_REMOVE, 1); + } static uint32_t ws_probe_init_time_get(protocol_interface_info_entry_t *cur) @@ -2061,12 +2193,14 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, uint8_t ll_address[16]; bool nud_proces = false; bool activate_nud = false; + bool child; + bool candidate_parent; protocol_interface_info_entry_t *cur = user_data; ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, entry_ptr->index); etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, entry_ptr->index); - if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry || ws_neighbor->negative_aro_send || entry_ptr->link_lifetime < WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) { + if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry || entry_ptr->link_lifetime <= WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) { return false; } @@ -2074,12 +2208,17 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) { + child = ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64); + candidate_parent = rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max); /* For parents ARO registration is sent in link timeout times * For candidate parents NUD is needed * For children NUD is sent only at very close to end */ - if (ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64) && - (time_from_start < WS_NEIGHBOR_NUD_TIMEOUT * 1.8)) { + if (!child && !candidate_parent) { + // No need for keep alive + return false; + } + if (child && (time_from_start < WS_NEIGHBOR_NUD_TIMEOUT * 1.8)) { /* This is our child with valid ARO registration send NUD if we are close to delete * * if ARO was received link is considered active so this is only in case of very long ARO registration times @@ -2090,11 +2229,6 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } - if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max)) { - //NUD Not needed for if neighbour is not parent candidate - return false; - } - if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) { activate_nud = true; } else { @@ -2264,11 +2398,11 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) ret_val = -4; goto init_fail; } - if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated) < 0) { + if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated, &ws_bootstrap_eapol_congestion_get) < 0) { ret_val = -4; goto init_fail; } - if (ws_pae_controller_configure(cur, &cur->ws_info->cfg->sec_timer, &cur->ws_info->cfg->sec_prot) < 0) { + if (ws_pae_controller_configure(cur, &cur->ws_info->cfg->sec_timer, &cur->ws_info->cfg->sec_prot, &cur->ws_info->cfg->timing) < 0) { ret_val = -4; goto init_fail; } @@ -2284,6 +2418,8 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) goto init_fail; } + cur->ipv6_neighbour_cache.link_mtu = cur->max_link_mtu = WS_MPX_MAX_MTU; + cur->if_up = ws_bootstrap_up; cur->if_down = ws_bootstrap_down; cur->ws_info->neighbor_storage = neigh_info; @@ -2364,7 +2500,11 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan set_request.value_size = sizeof(phy_rf_channel_configuration_s); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); // Set Ack wait duration - uint16_t ack_wait_symbols = WS_ACK_WAIT_SYMBOLS + (WS_TACK_MAX_MS * (rf_configs.datarate / 1000)); + uint8_t bits_per_symbol = 1; + if (rf_configs.modulation == M_OFDM) { + bits_per_symbol = 4; + } + uint16_t ack_wait_symbols = WS_ACK_WAIT_SYMBOLS + (WS_TACK_MAX_MS * (rf_configs.datarate / 1000) / bits_per_symbol); set_request.attr = macAckWaitDuration; set_request.value_pointer = &ack_wait_symbols; set_request.value_size = sizeof(ack_wait_symbols); @@ -2514,6 +2654,13 @@ static void ws_set_fhss_hop(protocol_interface_info_entry_t *cur) // Calculate own hop count. This method gets inaccurate when hop count increases. uint8_t own_hop = (own_rank - rank_inc) / rank_inc; ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, own_hop); + if (own_hop == 1) { + // Allow transmitting unicast frames only on TX slots in normal mode and always in expedited forwarding mode for first hop + ns_fhss_ws_set_tx_allowance_level(cur->ws_info->fhss_api, WS_TX_SLOT, WS_TX_ALWAYS); + } else { + // Allow transmitting unicast frames only on TX slots in normal and expedited forwarding mode for other hops + ns_fhss_ws_set_tx_allowance_level(cur->ws_info->fhss_api, WS_TX_SLOT, WS_TX_SLOT); + } tr_debug("own hop: %u, own rank: %u, rank inc: %u", own_hop, own_rank, rank_inc); } @@ -2546,6 +2693,63 @@ static void ws_address_parent_update(protocol_interface_info_entry_t *interface) ws_address_registration_update(interface, NULL); } +static void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) +{ + /* Possible problem with the parent connection + * Give some time for parent to rejoin and confirm the connection with ARO and DAO + */ + const rpl_dodag_conf_t *config = NULL; + uint32_t Imin_secs = 0; + + if (!ws_bootstrap_state_active(cur)) { + // If we are not in Active state no need to confirm parent + return; + } + + tr_info("RPL parent confirm"); + + if (!instance) { + // If we dont have instance we take any available to get reference + instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL); + } + + if (instance) { + config = rpl_control_get_dodag_config(instance); + } + + if (config) { + //dio imin Period caluclate in seconds + uint32_t Imin_ms = config->dio_interval_min < 32 ? (1ul << config->dio_interval_min) : 0xfffffffful; + //Covert to seconds and multiple by 2 so we give time to recovery so divide by 500 do that operation + Imin_secs = (Imin_ms + 499) / 500; + + if (Imin_secs > 0xffff) { + Imin_secs = 0xffff; + } + } + if (Imin_secs == 0) { + // If we dont have RPL configuration we assume conservative value + Imin_secs = 60; + } + + /*Speed up the ARO registration*/ + if (cur->ws_info->aro_registration_timer > Imin_secs) { + cur->ws_info->aro_registration_timer = Imin_secs; + } +} + +static void ws_rpl_parent_dis_callback(const uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance) +{ + (void) ll_parent_address; + protocol_interface_info_entry_t *cur = handle; + if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { + return; + } + //Multicast DIS from parent indicate that Parent is not valid in short time window possible + ws_bootstrap_parent_confirm(cur, instance); +} + + static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) { @@ -2553,6 +2757,15 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { return; } + + if (event == RPL_EVENT_POISON_FINISHED) { + //If we are waiting poison we will trig Discovery after couple seconds + if (cur->nwk_bootstrap_state == ER_RPL_NETWORK_LEAVING) { + cur->bootsrap_state_machine_cnt = 80; //Give 8 seconds time to send Poison + } + return; + } + // if waiting for RPL and if (event == RPL_EVENT_DAO_DONE) { // Trigger statemachine check @@ -2580,9 +2793,7 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) } // After successful DAO ACK connection to border router is verified - cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; - - + ws_common_border_router_alive_update(cur); } if (!cur->ws_info->trickle_pa_running || !cur->ws_info->trickle_pc_running) { @@ -2592,7 +2803,9 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) ws_set_fhss_hop(cur); // Set retry configuration for bootstrap ready state - ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES, WS_NUMBER_OF_CHANNEL_RETRIES); + ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES); + // Set TX failure request restart configuration + ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); } else if (event == RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS) { /* * RPL goes to passive mode, but does not require any extra changed @@ -2604,10 +2817,14 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) } else if (event == RPL_EVENT_LOCAL_REPAIR_START) { tr_debug("RPL local repair start"); - //Disable Asynchs - ws_bootstrap_asynch_trickle_stop(cur); - ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN); - + //Disable Async and go to state 4 to confirm parent connection + ws_bootstrap_parent_confirm(cur, NULL); + // Move to state 4 if we see issues with primary parent + if (ws_bootstrap_state_active(cur)) { + tr_info("Move state 4 to wait parent connection confirmation"); + ws_bootstrap_rpl_scan_start(cur); + ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN); + } } else if (event == RPL_EVENT_DAO_PARENT_ADD) { ws_address_parent_update(cur); } @@ -2822,7 +3039,7 @@ 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, cur); + rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback, ws_rpl_parent_dis_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 @@ -2832,6 +3049,7 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) 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); + rpl_control_set_force_tunnel(true); 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); } @@ -3025,12 +3243,14 @@ static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, u static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64) { - (void) target_eui_64; - if (result == AUTH_RESULT_OK) { - tr_debug("authentication success"); + tr_debug("authentication success eui64:%s", trace_array(target_eui_64, 8)); + if (target_eui_64) { + // Authentication was made contacting the authenticator + cur->ws_info->authentication_time = cur->ws_info->uptime; + } ws_bootstrap_event_configuration_start(cur); - } else if (result == AUTH_RESULT_ERR_TX_NO_ACK) { + } else if (result == AUTH_RESULT_ERR_TX_ERR) { // eapol parent selected is not working tr_debug("authentication TX failed"); @@ -3072,6 +3292,103 @@ static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface return previous_eui_64; } +static void ws_bootstrap_eapol_congestion_init(protocol_interface_info_entry_t *cur) +{ + random_early_detection_free(cur->llc_random_early_detection); + cur->llc_random_early_detection = NULL; + + if (cur->llc_random_early_detection == NULL) { + cur->llc_random_early_detection = random_early_detection_create( + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, + 100, RED_AVERAGE_WEIGHT_EIGHTH); + } + + random_early_detection_free(cur->llc_eapol_random_early_detection); + cur->llc_eapol_random_early_detection = NULL; + + if (cur->llc_eapol_random_early_detection == NULL) { + cur->llc_eapol_random_early_detection = random_early_detection_create( + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, + 100, RED_AVERAGE_WEIGHT_EIGHTH); + } +} + +static bool ws_bootstrap_eapol_congestion_get(protocol_interface_info_entry_t *cur, uint16_t active_supp) +{ + if (cur == NULL || cur->random_early_detection == NULL || cur->llc_random_early_detection == NULL || cur->llc_eapol_random_early_detection == NULL) { + return false; + } + + bool return_value = false; + static struct red_info_s *red_info = NULL; + uint16_t adaptation_average = 0; + uint16_t llc_average = 0; + uint16_t llc_eapol_average = 0; + uint16_t average_sum = 0; + uint8_t active_max = 0; + + //TODO implement API for HEAP info request + uint32_t heap_size; + const mem_stat_t *mem_stats = ns_dyn_mem_get_mem_stat(); + if (mem_stats) { + heap_size = mem_stats->heap_sector_size; + } else { + heap_size = 0; + } + + /* + * For different memory sizes the max simultaneous authentications will be + * 32k: (32k / 50k) * 2 + 1 = 1 + * 65k: (65k / 50k) * 2 + 1 = 3 + * 250k: (250k / 50k) * 2 + 1 = 11 + * 1000k: (1000k / 50k) * 2 + 1 = 41 + * 2000k: (2000k / 50k) * 2 + 1 = 50 (upper limit) + */ + active_max = (heap_size / 50000) * 2 + 1; + if (active_max > 50) { + active_max = 50; + } + + // Read the values for adaptation and LLC queues + adaptation_average = random_early_detetction_aq_read(cur->random_early_detection); + llc_average = random_early_detetction_aq_read(cur->llc_random_early_detection); + llc_eapol_average = random_early_detetction_aq_read(cur->llc_eapol_random_early_detection); + // Calculate combined average + average_sum = adaptation_average + llc_average + llc_eapol_average; + + // Maximum for active supplicants based on memory reached, fail + if (active_supp >= active_max) { + return_value = true; + goto congestion_get_end; + } + + // Always allow at least five negotiations (if memory does not limit) + if (active_supp < 5) { + goto congestion_get_end; + } + + if (red_info == NULL) { + red_info = random_early_detection_create( + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, + 100, RED_AVERAGE_WEIGHT_DISABLED); + } + if (red_info == NULL) { + goto congestion_get_end; + } + + // Check drop probability + average_sum = random_early_detetction_aq_calc(red_info, average_sum); + return_value = random_early_detection_congestion_check(red_info); + +congestion_get_end: + tr_info("Active supplicant limit, active: %i max: %i summed averageQ: %i adapt averageQ: %i LLC averageQ: %i LLC EAPOL averageQ: %i drop: %s", active_supp, active_max, average_sum, adaptation_average, llc_average, llc_eapol_average, return_value ? "T" : "F"); + + return return_value; +} + // Start configuration learning static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur) { @@ -3094,18 +3411,18 @@ static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur) { tr_debug("Start RPL learn"); + // Stop Trickle timers + ws_bootstrap_asynch_trickle_stop(cur); + // routers wait until RPL root is contacted ws_bootstrap_state_change(cur, ER_RPL_SCAN); + // Change state as the state is checked in state machine + cur->ws_info->rpl_state = RPL_EVENT_LOCAL_REPAIR_START; //For Large network and medium should do passive scan if (ws_cfg_network_config_get(cur) > CONFIG_SMALL) { // Set timeout for check to 30 - 60 seconds cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT); } - /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border - * Router for an interval of PAN_TIMEOUT, a node MUST assume failure of the PAN Border Router and MUST - * Transition to Join State 1 - */ - cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; } /* @@ -3132,6 +3449,12 @@ void ws_bootstrap_event_routing_ready(protocol_interface_info_entry_t *cur) { ws_bootsrap_event_trig(WS_ROUTING_READY, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); } + +void ws_bootstrap_event_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type) +{ + ws_bootsrap_event_trig(event_type, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); +} + void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *cur) { trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); @@ -3166,6 +3489,7 @@ static void ws_bootstrap_pan_advert_solicit(protocol_interface_info_entry_t *cur async_req.security.SecurityLevel = 0; + ws_stats_update(cur, STATS_WS_ASYNCH_TX_PAS, 1); ws_llc_asynch_request(cur, &async_req); } @@ -3182,6 +3506,7 @@ static void ws_bootstrap_pan_config_solicit(protocol_interface_info_entry_t *cur ws_set_asynch_channel_list(cur, &async_req); async_req.security.SecurityLevel = 0; + ws_stats_update(cur, STATS_WS_ASYNCH_TX_PCS, 1); ws_llc_asynch_request(cur, &async_req); } @@ -3211,9 +3536,9 @@ 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 = WS_ETX_MAX; //SET maxium value here if ETX is unknown + etx = WS_ETX_MAX; //SET maximum value here if ETX is unknown } else { - //Scale to 128 based ETX (local read retur 0x100 - 0xffff + //Scale to 128 based ETX (local read return 0x100 - 0xffff etx = etx >> 1; } // Make the 0xffff as maximum value @@ -3271,7 +3596,7 @@ static void ws_bootstrap_pan_advert(protocol_interface_info_entry_t *cur) cur->ws_info->pan_information.routing_cost = ws_bootstrap_routing_cost_calculate(cur); } - + ws_stats_update(cur, STATS_WS_ASYNCH_TX_PA, 1); ws_llc_asynch_request(cur, &async_req); } @@ -3300,6 +3625,7 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) async_req.security.KeyIndex = mac_helper_default_key_index_get(cur); } + ws_stats_update(cur, STATS_WS_ASYNCH_TX_PC, 1); ws_llc_asynch_request(cur, &async_req); } @@ -3315,6 +3641,7 @@ static int8_t ws_bootstrap_backbone_ip_addr_get(protocol_interface_info_entry_t return -1; } + static void ws_bootstrap_event_handler(arm_event_s *event) { ws_bootsrap_event_type_e event_type; @@ -3331,7 +3658,6 @@ static void ws_bootstrap_event_handler(arm_event_s *event) break; case WS_DISCOVERY_START: tr_info("Discovery start"); - protocol_mac_reset(cur); ws_llc_reset(cur); lowpan_adaptation_interface_reset(cur->id); @@ -3339,6 +3665,8 @@ static void ws_bootstrap_event_handler(arm_event_s *event) cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; cur->mac_parameters->mac_default_key_index = 0; + ipv6_destination_cache_clean(cur->id); + // Clear parent blacklist blacklist_clear(); @@ -3364,9 +3692,6 @@ static void ws_bootstrap_event_handler(arm_event_s *event) ws_bootstrap_ip_stack_reset(cur); ws_pae_controller_auth_init(cur); - // Randomize fixed channels. Only used if channel plan is fixed. - cur->ws_info->cfg->fhss.fhss_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); - cur->ws_info->cfg->fhss.fhss_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); if (cur->ws_info->cfg->gen.network_pan_id == 0xffff) { cur->ws_info->network_pan_id = randLIB_get_random_in_range(0, 0xfffd); } else { @@ -3413,8 +3738,17 @@ static void ws_bootstrap_event_handler(arm_event_s *event) // Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address) ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); + // Initialize eapol congestion tracking + ws_bootstrap_eapol_congestion_init(cur); + // Set retry configuration for bootstrap ready state - ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES, WS_NUMBER_OF_CHANNEL_RETRIES); + ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES); + + // Set TX failure request restart configuration + ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); + + // Set CSMA-CA backoff configuration + ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE); ws_bootstrap_event_operation_start(cur); break; @@ -3426,7 +3760,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event) ws_bootstrap_network_discovery_configure(cur); ws_bootstrap_fhss_activate(cur); // Set retry configuration for discovery state - ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES_BOOTSTRAP, WS_NUMBER_OF_CHANNEL_RETRIES_BOOTSTRAP); + ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES_BOOTSTRAP); + // Set TX failure request restart configuration for discovery state + ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX_BOOTSTRAP, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); + // Set CSMA-CA backoff configuration + ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE); // Start network scan ws_bootstrap_start_discovery(cur); break; @@ -3454,6 +3792,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event) ws_bootstrap_event_routing_ready(cur); } else { ws_bootstrap_rpl_scan_start(cur); + /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border + * Router for an interval of PAN_TIMEOUT, a node MUST assume failure of the PAN Border Router and MUST + * Transition to Join State 1 + */ + ws_common_border_router_alive_update(cur); } break; case WS_ROUTING_READY: @@ -3467,6 +3810,12 @@ static void ws_bootstrap_event_handler(arm_event_s *event) ws_bootstrap_advertise_start(cur); ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE); break; + case WS_FAST_DISCONNECT: + ws_bootstrap_disconnect(cur, WS_FAST_DISCONNECT); + break; + case WS_NORMAL_DISCONNECT: + ws_bootstrap_disconnect(cur, WS_NORMAL_DISCONNECT); + break; default: tr_err("Invalid event received"); @@ -3559,6 +3908,7 @@ void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur) if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { // RPL routing is ready + cur->ws_info->connected_time = cur->ws_info->uptime; ws_bootstrap_event_routing_ready(cur); } else if (!rpl_control_have_dodag(cur->rpl_domain)) { // RPL not ready send DIS message if possible @@ -3658,6 +4008,10 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur) // Bootstrap_done event to application nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); break; + case ER_RPL_NETWORK_LEAVING: + tr_debug("WS SM:RPL Leaving ready trigger discovery"); + ws_bootstrap_event_discovery_start(cur); + break; default: tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state); } @@ -3743,9 +4097,10 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s } } else { // Border router has timed out + //Clear Timeout timer cur->ws_info->pan_timeout_timer = 0; tr_warn("Border router has timed out"); - ws_bootstrap_event_discovery_start(cur); + ws_bootstrap_event_disconnect(cur, WS_FAST_DISCONNECT); } } if (cur->ws_info->aro_registration_timer) { @@ -3767,6 +4122,19 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s cur->ws_info->ws_bsi_block.old_bsi = 0; } } + /*Update join state statistics*/ + if (ws_bootstrap_state_discovery(cur)) { + ws_stats_update(cur, STATS_WS_STATE_1, 1); + } else if (ws_bootstrap_state_authenticate(cur)) { + ws_stats_update(cur, STATS_WS_STATE_2, 1); + } else if (ws_bootstrap_state_configure(cur)) { + ws_stats_update(cur, STATS_WS_STATE_3, 1); + } else if (ws_bootstrap_state_wait_rpl(cur)) { + ws_stats_update(cur, STATS_WS_STATE_4, 1); + } else if (ws_bootstrap_state_active(cur)) { + ws_stats_update(cur, STATS_WS_STATE_5, 1); + } + cur->ws_info->uptime++; ws_llc_timer_seconds(cur, seconds); @@ -3798,7 +4166,7 @@ void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *inter } } -int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr) +int ws_bootstrap_stack_info_get(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr) { ws_neighbor_class_entry_t *ws_neighbour = NULL; @@ -3808,14 +4176,11 @@ int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_ if (mac_parent) { ws_neighbour = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_parent->index); - - memcpy(info_ptr->parent, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(info_ptr->parent + 8, mac_parent->mac64, 8); - info_ptr->parent[8] ^= 2; + ws_bootsrap_create_ll_address(info_ptr->parent, mac_parent->mac64); } if (ws_neighbour) { - info_ptr->rsl_in = ws_neighbour->rsl_in; - info_ptr->rsl_out = ws_neighbour->rsl_out; + info_ptr->rsl_in = ws_neighbor_class_rsl_in_get(ws_neighbour); + info_ptr->rsl_out = ws_neighbor_class_rsl_out_get(ws_neighbour); info_ptr->routing_cost = ws_neighbour->routing_cost; } info_ptr->device_min_sens = DEVICE_MIN_SENS; @@ -3834,6 +4199,78 @@ int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_ return 0; } +int ws_bootstrap_neighbor_info_get(protocol_interface_info_entry_t *cur, ws_neighbour_info_t *neighbor_ptr, uint16_t table_max) +{ + uint8_t count = 0; + if (!neighbor_ptr) { + // Return the aount of neighbors. + for (int n = 0; n < mac_neighbor_info(cur)->list_total_size; n++) { + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(cur), n); + if (mac_entry && mac_entry->lifetime && mac_entry->lifetime != 0xffffffff) { + count++; + } + } + return count; + } + + if (table_max > mac_neighbor_info(cur)->list_total_size) { + table_max = mac_neighbor_info(cur)->list_total_size; + } + + for (int n = 0; n < mac_neighbor_info(cur)->list_total_size; n++) { + if (count > table_max) { + break; + } + + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(cur), n); + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, n); + if (mac_entry && ws_neighbor && mac_entry->lifetime && mac_entry->lifetime != 0xffffffff) { + // Active neighbor entry + uint8_t ll_address[16]; + memset(neighbor_ptr + count, 0, sizeof(ws_neighbour_info_t)); + neighbor_ptr[count].lifetime = mac_entry->lifetime; + + neighbor_ptr[count].rsl_in = ws_neighbor_class_rsl_in_get(ws_neighbor); + neighbor_ptr[count].rsl_out = ws_neighbor_class_rsl_out_get(ws_neighbor); + + // ETX is shown calculated as 8 bit integer, but more common way is to use 7 bit such that 128 means ETX:1.0 + neighbor_ptr[count].etx = etx_local_etx_read(cur->id, mac_entry->index); + if (neighbor_ptr[count].etx != 0xffff) { + neighbor_ptr[count].etx = neighbor_ptr[count].etx >> 1; + } + ws_bootsrap_create_ll_address(ll_address, mac_entry->mac64); + memcpy(neighbor_ptr[count].link_local_address, ll_address, 16); + + if (rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max)) { + neighbor_ptr[count].type = WS_CANDIDATE_PARENT; + } + neighbor_ptr[count].rpl_rank = rpl_control_neighbor_info_get(cur, ll_address, neighbor_ptr[count].global_address); + + if (mac_entry->link_role == PRIORITY_PARENT_NEIGHBOUR) { + neighbor_ptr[count].type = WS_PRIMARY_PARENT; + } + if (mac_entry->link_role == SECONDARY_PARENT_NEIGHBOUR) { + neighbor_ptr[count].type = WS_SECONDARY_PARENT; + } + if (mac_entry->link_role == CHILD_NEIGHBOUR) { + neighbor_ptr[count].type = WS_CHILD; + } + + ipv6_neighbour_t *IPv6_neighbor = ipv6_neighbour_get_registered_by_eui64(&cur->ipv6_neighbour_cache, mac_entry->mac64); + if (IPv6_neighbor) { + //This is a child + neighbor_ptr[count].type = WS_CHILD; + memcpy(neighbor_ptr[count].global_address, IPv6_neighbor->ip_address, 16); + // Child lifetimes are based on Registration times not a link time + neighbor_ptr[count].lifetime = IPv6_neighbor->lifetime; + } + count++; + } + } + + // Go through list + return count; +} //Calculate max_packet queue size static uint16_t ws_bootstrap_define_congestin_max_threshold(uint32_t heap_total_size, uint16_t packet_size, uint16_t packet_per_seconds, uint32_t max_delay, uint16_t min_packet_queue_size, uint16_t max_packet_queue_size) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h index 7be0655ca3c..535092501d3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h @@ -24,7 +24,9 @@ typedef enum { WS_DISCOVERY_START, /**< discovery start*/ WS_CONFIGURATION_START, /**< configuration learn start*/ WS_OPERATION_START, /**< active operation start*/ - WS_ROUTING_READY /**< RPL routing connected to BR*/ + WS_ROUTING_READY, /**< RPL routing connected to BR*/ + WS_FAST_DISCONNECT, /**< Do fast timeout after Border router timeout*/ + WS_NORMAL_DISCONNECT /**< Border have been rebooted so Slow poison Process*/ } ws_bootsrap_event_type_e; #ifdef HAVE_WS @@ -34,6 +36,7 @@ struct ws_us_ie; struct ws_bs_ie; struct ws_neighbor_class_entry; struct ws_stack_info; +struct ws_neighbour_info; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); @@ -60,6 +63,8 @@ void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur); void ws_bootstrap_event_routing_ready(protocol_interface_info_entry_t *cur); +void ws_bootstrap_event_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type); + void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *cur); void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); @@ -92,7 +97,9 @@ void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry void ws_bootstrap_neighbor_set_stable(struct protocol_interface_info_entry *interface, const uint8_t *src64); -int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr); +int ws_bootstrap_stack_info_get(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr); + +int ws_bootstrap_neighbor_info_get(protocol_interface_info_entry_t *cur, struct ws_neighbour_info *neighbor_ptr, uint16_t table_max); void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_entry *interface, const uint8_t *src64, uint32_t valid_time); @@ -106,7 +113,8 @@ void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_ent #define ws_bootstrap_neighbor_set_stable(interface, src64) #define ws_bootstrap_primary_parent_update(interface, neighbor) #define ws_bootstrap_secondary_parent_update(interface) -#define ws_bootstrap_get_info(cur, info_ptr) +#define ws_bootstrap_stack_info_get(cur, info_ptr) +#define ws_bootstrap_neighbor_info_get(cur, neighbor_ptr, count) #endif //HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c index 40e46940f30..32254b214b6 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c @@ -98,10 +98,10 @@ typedef struct cfg_devices_in_config { * */ const cfg_devices_in_config_t devices_by_datarate[] = { - { 1, 4, 10, 25}, // Configuration for 50 -100kbs - { 1, 8, 15, 25}, // Configuration for 150kbs - 200kbs - { 2, 15, 25, 50}, // Configuration for 300kbs - { 3, 20, 40, 100}, // Configuration for 600kbs - 2400kbs + { 1, 5, 10, 25}, // Configuration for 50 -100kbs + { 1, 10, 20, 40}, // Configuration for 150kbs - 200kbs + { 1, 15, 30, 60}, // Configuration for 300kbs + { 2, 20, 50, 100}, // Configuration for 600kbs - 2400kbs }; @@ -301,6 +301,8 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ set_function(&nw_size_cfg); } + uint8_t cfg_network_size = cfg->network_size; + /* If no longer in an automatic network size mode, frees automatic configuration, so that new configuration is set */ if (nw_size_external_cfg && old_network_size == NETWORK_SIZE_AUTOMATIC) { @@ -309,7 +311,7 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ } uint8_t set_flags = 0; - if (cfg->network_size == NETWORK_SIZE_AUTOMATIC) { + if (cfg_network_size == NETWORK_SIZE_AUTOMATIC) { set_flags = CFG_FLAGS_DISABLE_VAL_SET; } /* Sets values if changed or network size has been previously automatic (to make sure @@ -336,12 +338,45 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ } // If is in an automatic network size mode, updates automatic configuration - if (cfg->network_size == NETWORK_SIZE_AUTOMATIC && cur) { + if (cfg_network_size == NETWORK_SIZE_AUTOMATIC && cur) { ws_cfg_network_size_configure(cur, cur->ws_info->pan_information.pan_size); } return CFG_SETTINGS_OK; } +static uint8_t ws_cfg_config_get_by_size(protocol_interface_info_entry_t *cur, uint8_t network_size) +{ + (void)cur; + + ws_phy_cfg_t phy_cfg; + if (ws_cfg_phy_get(&phy_cfg, NULL) < 0) { + return CONFIG_SMALL; + } + uint32_t data_rate = ws_common_datarate_get_from_phy_mode(phy_cfg.phy_mode_id, phy_cfg.operating_mode); + + uint8_t index; + if (data_rate < 150000) { + index = 0; + } else if (data_rate < 300000) { + index = 1; + } else if (data_rate < 600000) { + index = 2; + } else { + index = 3; + } + + if (network_size == NETWORK_SIZE_CERTIFICATE) { + return CONFIG_CERTIFICATE; + } else if (network_size <= devices_by_datarate[index].max_for_small) { + return CONFIG_SMALL; + } else if (network_size <= devices_by_datarate[index].max_for_medium) { + return CONFIG_MEDIUM; + } else if (network_size <= devices_by_datarate[index].max_for_large) { + return CONFIG_LARGE; + } + return CONFIG_XLARGE; +} + int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint16_t network_size) { // Read settings that are affected by network size @@ -362,18 +397,18 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 memcpy(nw_size_external_cfg, &new_nw_size_cfg, sizeof(ws_cfg_nw_size_t)); } - // Small - if (network_size < 100) { - // Automatic + network_size = network_size / 100; + if (network_size == 0) { + network_size = 1; + } + + if (ws_cfg_config_get_by_size(cur, network_size) == CONFIG_SMALL) { ws_cfg_network_size_config_set_small(&new_nw_size_cfg); - } else if (network_size < 800) { - // Medium + } else if (ws_cfg_config_get_by_size(cur, network_size) == CONFIG_MEDIUM) { ws_cfg_network_size_config_set_medium(&new_nw_size_cfg); - } else if (network_size < 1500) { - // Medium + } else if (ws_cfg_config_get_by_size(cur, network_size) == CONFIG_LARGE) { ws_cfg_network_size_config_set_large(&new_nw_size_cfg); } else { - // Large ws_cfg_network_size_config_set_xlarge(&new_nw_size_cfg); } @@ -398,33 +433,8 @@ cfg_network_size_type_e ws_cfg_network_config_get(protocol_interface_info_entry_ if (ws_cfg_gen_get(&cfg, NULL) < 0) { return CONFIG_SMALL; } - ws_phy_cfg_t phy_cfg; - if (ws_cfg_phy_get(&phy_cfg, NULL) < 0) { - return CONFIG_SMALL; - } - uint32_t data_rate = ws_get_datarate_using_operating_mode(phy_cfg.operating_mode); - uint8_t index; - if (data_rate < 150000) { - index = 0; - } else if (data_rate < 300000) { - index = 1; - } else if (data_rate < 600000) { - index = 2; - } else { - index = 3; - } - - if (cfg.network_size == NETWORK_SIZE_CERTIFICATE) { - return CONFIG_CERTIFICATE; - } else if (cfg.network_size <= devices_by_datarate[index].max_for_small) { - return CONFIG_SMALL; - } else if (cfg.network_size <= devices_by_datarate[index].max_for_medium) { - return CONFIG_MEDIUM; - } else if (cfg.network_size <= devices_by_datarate[index].max_for_large) { - return CONFIG_LARGE; - } - return CONFIG_XLARGE; + return ws_cfg_config_get_by_size(cur, cfg.network_size); } @@ -448,6 +458,7 @@ static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg) cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.rpl_default_lifetime = WS_RPL_DEFAULT_LIFETIME; cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL; // EAPOL configuration @@ -456,8 +467,6 @@ static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg) cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL; - cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; @@ -492,6 +501,7 @@ static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg) cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10 cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.rpl_default_lifetime = WS_RPL_DEFAULT_LIFETIME_MEDIUM; cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM; // EAPOL configuration @@ -500,8 +510,6 @@ static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg) cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM; - cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; cfg->sec_prot.initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; cfg->sec_prot.initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; @@ -522,7 +530,7 @@ static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; // Configure the Wi-SUN timing trickle parameters - cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 1; // 120 seconds cfg->timing.disc_trickle_imax = 1536; // 1536 seconds; 25 minutes cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_LARGE_NETWORK_TIMEOUT; @@ -530,11 +538,12 @@ static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT; // RPL configuration - cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 18; 262s, 4.5min + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 18; 256s, 4.5min cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 3; 2048s, 34min cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10 cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.rpl_default_lifetime = WS_RPL_DEFAULT_LIFETIME_LARGE; cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE; // EAPOL configuration @@ -543,8 +552,6 @@ static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE; - cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER; cfg->sec_prot.initial_key_imin = LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; cfg->sec_prot.initial_key_imax = LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; @@ -579,6 +586,7 @@ static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_XLARGE; // 10 cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.rpl_default_lifetime = WS_RPL_DEFAULT_LIFETIME_XLARGE; cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE; // EAPOL configuration @@ -587,8 +595,6 @@ static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE; - cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER; cfg->sec_prot.initial_key_imin = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; cfg->sec_prot.initial_key_imax = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; @@ -622,6 +628,7 @@ static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled cfg->bbr.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE; cfg->bbr.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.rpl_default_lifetime = WS_RPL_DEFAULT_LIFETIME; cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL; // EAPOL configuration @@ -630,8 +637,6 @@ static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL; - cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; @@ -698,6 +703,7 @@ int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, w } ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_gen_cfg_t), "gen"); + cfg->network_size = new_cfg->network_size; if (&cfg->network_name != &new_cfg->network_name) { strncpy(cfg->network_name, new_cfg->network_name, 32); } @@ -883,6 +889,7 @@ int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t * cur->ws_info->trickle_params_pan_discovery.Imax = new_cfg->disc_trickle_imax * 10; cur->ws_info->trickle_params_pan_discovery.k = new_cfg->disc_trickle_k; cur->ws_info->trickle_params_pan_discovery.TimerExpirations = TRICKLE_EXPIRATIONS_INFINITE; + ws_pae_controller_configure(cur, NULL, NULL, new_cfg); } if (cfg == new_cfg) { @@ -909,6 +916,7 @@ static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg) cfg->dio_redundancy_constant = 10; cfg->dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->rpl_default_lifetime = WS_RPL_DEFAULT_LIFETIME_MEDIUM; cfg->dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM; return CFG_SETTINGS_OK; @@ -932,7 +940,8 @@ int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg) cfg->dio_redundancy_constant != new_cfg->dio_redundancy_constant || cfg->dag_max_rank_increase != new_cfg->dag_max_rank_increase || cfg->min_hop_rank_increase != new_cfg->min_hop_rank_increase || - cfg->dhcp_address_lifetime != new_cfg->dhcp_address_lifetime) { + cfg->dhcp_address_lifetime != new_cfg->dhcp_address_lifetime || + cfg->rpl_default_lifetime != new_cfg->rpl_default_lifetime) { return CFG_SETTINGS_CHANGED; } @@ -954,7 +963,7 @@ int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, w // cur is optional, default values are for Wi-SUN small network parameters, ws_bbr_rpl_config(cur, new_cfg->dio_interval_min, new_cfg->dio_interval_doublings, new_cfg->dio_redundancy_constant, new_cfg->dag_max_rank_increase, - new_cfg->min_hop_rank_increase); + new_cfg->min_hop_rank_increase, new_cfg->rpl_default_lifetime); ws_bbr_dhcp_address_lifetime_set(cur, new_cfg->dhcp_address_lifetime); } @@ -1210,7 +1219,7 @@ int8_t ws_cfg_sec_timer_set(protocol_interface_info_entry_t *cur, ws_sec_timer_c } if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { - ws_pae_controller_configure(cur, new_cfg, NULL); + ws_pae_controller_configure(cur, new_cfg, NULL, NULL); } if (cfg == new_cfg) { @@ -1230,7 +1239,8 @@ static int8_t ws_cfg_sec_prot_default_set(ws_sec_prot_cfg_t *cfg) cfg->sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot_trickle_timer_exp = 2; cfg->sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM; + cfg->max_simult_sec_neg_tx_queue_min = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MIN; + cfg->max_simult_sec_neg_tx_queue_max = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MAX; cfg->initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; cfg->initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; cfg->initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; @@ -1256,7 +1266,8 @@ int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_c cfg->sec_prot_trickle_imax != new_cfg->sec_prot_trickle_imax || cfg->sec_prot_trickle_timer_exp != new_cfg->sec_prot_trickle_timer_exp || cfg->sec_prot_retry_timeout != new_cfg->sec_prot_retry_timeout || - cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication || + cfg->max_simult_sec_neg_tx_queue_min != new_cfg->max_simult_sec_neg_tx_queue_min || + cfg->max_simult_sec_neg_tx_queue_max != new_cfg->max_simult_sec_neg_tx_queue_max || cfg->initial_key_retry_delay != new_cfg->initial_key_retry_delay || cfg->initial_key_imin != new_cfg->initial_key_retry_delay || cfg->initial_key_imax != new_cfg->initial_key_retry_delay || @@ -1277,7 +1288,7 @@ int8_t ws_cfg_sec_prot_set(protocol_interface_info_entry_t *cur, ws_sec_prot_cfg } if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { - ws_pae_controller_configure(cur, NULL, new_cfg); + ws_pae_controller_configure(cur, NULL, new_cfg, NULL); } if (cfg == new_cfg) { @@ -1438,7 +1449,7 @@ uint32_t ws_cfg_neighbour_temporary_lifetime_get(void) } void ws_cfg_neighbour_temporary_lifetime_set(uint32_t lifetime) { - if (lifetime >= WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME || lifetime == 0) { + if (lifetime > WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME || lifetime == 0) { if (lifetime > WS_NEIGHBOR_LINK_TIMEOUT) { lifetime = WS_NEIGHBOR_LINK_TIMEOUT; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h index 763d1ff56fe..6b5dd98bce6 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h @@ -64,6 +64,7 @@ typedef struct ws_bbr_cfg_s { uint16_t dag_max_rank_increase; uint16_t min_hop_rank_increase; uint32_t dhcp_address_lifetime; /**< DHCP address lifetime in seconds minimum 2 hours and maximum as days hours*/ + uint32_t rpl_default_lifetime; /**< RPL default lifetime value minimum from 30 minutes to 16 hours*/ } ws_bbr_cfg_t; /** @@ -114,7 +115,8 @@ typedef struct ws_sec_prot_cfg_s { uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */ uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */ uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */ - uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */ + uint16_t max_simult_sec_neg_tx_queue_min; /**< PAE authenticator max simultaneous security negotiations TX queue minimum */ + uint16_t max_simult_sec_neg_tx_queue_max; /**< PAE authenticator max simultaneous security negotiations TX queue maximum */ uint16_t initial_key_retry_delay; /**< Delay before starting initial key trickle; seconds; default 120 */ uint16_t initial_key_imin; /**< Initial key trickle Imin; seconds; default 360 */ uint16_t initial_key_imax; /**< Initial key trickle Imax; seconds; default 720 */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c index bf1bca224fb..4a77f37bab6 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c @@ -34,6 +34,7 @@ #include "6LoWPAN/ws/ws_bbr_api_internal.h" #include "6LoWPAN/ws/ws_pae_controller.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_stats.h" #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "Service_Libs/blacklist/blacklist.h" @@ -223,7 +224,7 @@ phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t oper int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, ws_hopping_schedule_t *hopping_schdule) { (void)cur; - if (ws_get_datarate_using_operating_mode(hopping_schdule->operating_mode) == 0) { + if (ws_common_datarate_get_from_phy_mode(hopping_schdule->phy_mode_id, hopping_schdule->operating_mode) == 0) { //Unsupported operation mode return -1; } @@ -629,6 +630,7 @@ uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *inte ws_common_neighbour_address_reg_link_update(interface, eui64, link_lifetime); tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); + ws_stats_update(interface, STATS_WS_CHILD_ADD, 1); return ARO_SUCCESS; } @@ -639,9 +641,7 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con 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 + ws_bootstrap_mac_neighbor_short_time_set(interface, eui64, WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME); return true; } @@ -663,11 +663,37 @@ uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur) return latency; } +uint32_t ws_common_datarate_get_from_phy_mode(uint8_t phy_mode_id, uint8_t operating_mode) +{ + if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || + ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || + ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || + ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + return ws_get_datarate_using_phy_mode_id(phy_mode_id); + } + return ws_get_datarate_using_operating_mode(operating_mode); +} + uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur) { - return ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + return ws_common_datarate_get_from_phy_mode(cur->ws_info->hopping_schdule.phy_mode_id, cur->ws_info->hopping_schdule.operating_mode); +} + +uint32_t ws_common_usable_application_datarate_get(protocol_interface_info_entry_t *cur) +{ + /* Usable data rate is a available data rate when removed ACK and wait times required to send a packet + * + * Estimated to be around 70% with following assumptions with 150kbs data rate + * Average ACK size 48 bytes + * Average tACK 2ms + * Average CCA check time + processing 7ms + * Delays in bytes with 150kbs data rate 168 + 48 bytes for ACK 216 bytes + * Usable data rate is 1 - 216/(216 + 500) about 70% + */ + return 70 * ws_common_datarate_get_from_phy_mode(cur->ws_info->hopping_schdule.phy_mode_id, cur->ws_info->hopping_schdule.operating_mode) / 100; } + uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur) { uint32_t network_size_estimate = 100; @@ -680,6 +706,30 @@ uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cu return network_size_estimate; } +uint32_t ws_common_connected_time_get(protocol_interface_info_entry_t *cur) +{ + if (!ws_info(cur)) { + return 0; + } + if (cur->ws_info->connected_time == 0) { + // We are not connected + return 0; + } + return cur->ws_info->uptime - cur->ws_info->connected_time; +} + +uint32_t ws_common_authentication_time_get(protocol_interface_info_entry_t *cur) +{ + if (!ws_info(cur)) { + return 0; + } + if (cur->ws_info->authentication_time == 0) { + // Authentication was not done when joined to network so time is not known + return 0; + } + return cur->ws_info->uptime - cur->ws_info->authentication_time; +} + void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) { ws_bootstrap_primary_parent_update(interface, neighbor); @@ -690,4 +740,14 @@ void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interfac ws_bootstrap_secondary_parent_update(interface); } +void ws_common_border_router_alive_update(protocol_interface_info_entry_t *interface) +{ + if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + return; + } + + // After successful DAO ACK connection to border router is verified + interface->ws_info->pan_timeout_timer = interface->ws_info->cfg->timing.pan_timeout; +} + #endif // HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h index c4f92f53816..2dda3beac82 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h @@ -97,7 +97,10 @@ typedef struct ws_info_s { ws_bsi_block_t ws_bsi_block; uint16_t aro_registration_timer; /**< Aro registration timer */ uint16_t rpl_version_timer; /**< RPL version update timeout */ - uint32_t pan_timeout_timer; /**< routers will fallback to previous state after this */ + uint32_t pan_timeout_timer; /**< routers will fallback to previous state after this */ + uint32_t uptime; /**< Seconds after interface has been started */ + uint32_t authentication_time; /**< When the last authentication was performed */ + uint32_t connected_time; /**< Time we have been connected to network */ uint32_t pan_config_sol_max_timeout; uint8_t gtkhash[32]; uint16_t network_pan_id; @@ -164,15 +167,25 @@ uint32_t ws_common_version_timeout_get(uint8_t config); uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur); +uint32_t ws_common_datarate_get_from_phy_mode(uint8_t phy_mode_id, uint8_t operating_mode); + uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur); +uint32_t ws_common_usable_application_datarate_get(protocol_interface_info_entry_t *cur); + uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur); +uint32_t ws_common_connected_time_get(protocol_interface_info_entry_t *cur); + +uint32_t ws_common_authentication_time_get(protocol_interface_info_entry_t *cur); + void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface); uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size); +void ws_common_border_router_alive_update(protocol_interface_info_entry_t *interface); + #define ws_info(cur) ((cur)->ws_info) #else #define ws_info(cur) ((ws_info_t *) NULL) @@ -185,10 +198,15 @@ uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size); #define ws_common_allow_child_registration(cur, eui64, aro_timeout) (2) #define ws_common_negative_aro_mark(interface, eui64)(false) #define ws_common_latency_estimate_get(cur) 0 +#define ws_common_datarate_get_from_phy_mode(phy_mode_id, operating_mode) 0 #define ws_common_datarate_get(cur) 0 +#define ws_common_usable_application_datarate_get(cur) 0 #define ws_common_network_size_estimate_get(cur) 0 +#define ws_common_connected_time_get(cur) 0 +#define ws_common_authentication_time_get(cur) 0 #define ws_common_primary_parent_update(interface, neighbor) #define ws_common_secondary_parent_update(interface) +#define ws_common_border_router_alive_update(interface) ((void) 0) #endif //HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h index 89a698b3d3c..1657d9ee6b8 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h @@ -239,6 +239,13 @@ typedef struct ws_bs_ie { #define MPX_KEY_MANAGEMENT_ENC_USER_ID 0x0001 /**< MPX Key management user ID */ #define MPX_LOWPAN_ENC_USER_ID 0xA0ED /**< MPX Lowpan User Id */ +/* + * Wi-SUN MPX MTU size + * + */ + +#define WS_MPX_MAX_MTU 1576 + #define WS_FAN_VERSION_1_0 1 #define WS_NEIGHBOR_LINK_TIMEOUT 2200 @@ -319,10 +326,10 @@ typedef struct ws_bs_ie { /* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). Default 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts). - * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts + * At least 4 request restarts must be used: (Initial channel + WS_TX_REQUEST_RESTART_MAX) * MAC attempts = (1+4)*4=20 attempts * * Valid settings could be for example: - * WS_MAX_FRAME_RETRIES WS_NUMBER_OF_CHANNEL_RETRIES Total attempts + * WS_MAX_FRAME_RETRIES WS_TX_REQUEST_RESTART_MAX Total attempts * 0 19 1+0*1+19=20 * 1 9 1+1*1+9=20 * 2 6 1+2*1+6=21 @@ -331,16 +338,28 @@ typedef struct ws_bs_ie { */ // This configuration is used when bootstrap is ready #define WS_MAX_FRAME_RETRIES 3 -#define WS_NUMBER_OF_CHANNEL_RETRIES 4 // This configuration is used during bootstrap -#define WS_MAX_FRAME_RETRIES_BOOTSTRAP 0 -#define WS_NUMBER_OF_CHANNEL_RETRIES_BOOTSTRAP 19 +#define WS_MAX_FRAME_RETRIES_BOOTSTRAP 0 +// Configuring data request restart allows MAC to push failed packet back to MAC TX queue up to WS_CCA_REQUEST_RESTART_MAX times for CCA failure and WS_TX_REQUEST_RESTART_MAX for TX failure. +// Packet cannot be taken back to transmission before it has finished the blacklist period. +#define WS_CCA_REQUEST_RESTART_MAX 9 +#define WS_TX_REQUEST_RESTART_MAX 4 +#define WS_TX_REQUEST_RESTART_MAX_BOOTSTRAP 19 +#define WS_REQUEST_RESTART_BLACKLIST_MIN 20 +#define WS_REQUEST_RESTART_BLACKLIST_MAX 300 -#if (1 + WS_MAX_FRAME_RETRIES) * (1 + WS_NUMBER_OF_CHANNEL_RETRIES) < 20 +#if (1 + WS_MAX_FRAME_RETRIES) * (1 + WS_TX_REQUEST_RESTART_MAX) < 20 #warning "MAX frame retries set too low" #endif +// Total CCA attempts: 1 + WS_MAX_CSMA_BACKOFFS +#define WS_MAX_CSMA_BACKOFFS 0 + +// Use minimum possible CSMA-CA backoffs +#define WS_MAC_MIN_BE 1 +#define WS_MAC_MAX_BE 1 + /* * Automatic CCA threshold: default threshold and range in dBm. */ @@ -373,4 +392,5 @@ typedef struct ws_bs_ie { #define BR_EAPOL_RELAY_SOCKET_PORT 10255 #define PAE_AUTH_SOCKET_PORT 10254 + #endif /* WS_COMMON_DEFINES_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h index f202cfea2fe..fb2e23ca275 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h @@ -50,6 +50,11 @@ #define WS_RPL_MIN_HOP_RANK_INCREASE 196 #define WS_RPL_MAX_HOP_RANK_INCREASE 2048 +#define WS_RPL_DEFAULT_LIFETIME (3600*2) // 2 hours +#define WS_RPL_DEFAULT_LIFETIME_MEDIUM (3600*4) // 4 hours +#define WS_RPL_DEFAULT_LIFETIME_LARGE (3600*8) // 8 hours +#define WS_RPL_DEFAULT_LIFETIME_XLARGE (3600*12) // 12 hours + #define WS_DHCP_ADDRESS_LIFETIME_SMALL 2*3600 // small networks less than devices 100 #define WS_DHCP_ADDRESS_LIFETIME_MEDIUM 12*3600 // Medium size networks from 100 - 1000 device networks #define WS_DHCP_ADDRESS_LIFETIME_LARGE 24*3600 // Large size networks 1000 + device networks @@ -60,7 +65,7 @@ /* * RPL DAO timeout maximum value. This will force DAO timeout to happen before this time */ -#define WS_RPL_DAO_MAX_TIMOUT (3600*2) +#define WS_RPL_DAO_MAX_TIMOUT (3600*12) /* Border router version change interval * @@ -90,9 +95,9 @@ * */ -#define PAN_VERSION_SMALL_NETWORK_TIMEOUT 32*60 +#define PAN_VERSION_SMALL_NETWORK_TIMEOUT 30*60 -#define PAN_VERSION_MEDIUM_NETWORK_TIMEOUT 64*60 +#define PAN_VERSION_MEDIUM_NETWORK_TIMEOUT 60*60 #define PAN_VERSION_LARGE_NETWORK_TIMEOUT 90*60 @@ -249,9 +254,8 @@ extern uint8_t DEVICE_MIN_SENS; #define SEC_PROT_TIMER_EXPIRATIONS 2 // Number of retries // Maximum number of simultaneous security negotiations -#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL 20 -#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM 20 -#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE 50 +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MIN 64 +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MAX 192 /* * Security protocol timer configuration parameters @@ -286,7 +290,7 @@ extern uint8_t DEVICE_MIN_SENS; // Large network trickle values for sending of initial EAPOL-key #define LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */ #define LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200 -#define LARGE_NW_INITIAL_KEY_RETRY_COUNT 4 +#define LARGE_NW_INITIAL_KEY_RETRY_COUNT 3 // Very slow network values for sending of initial EAPOL-key #define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.c index b32892eaed2..e5c2f64c843 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.c @@ -214,7 +214,19 @@ int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_data->msdu_handle++; - eapol_pdu_data->mpx_api->mpx_data_request(eapol_pdu_data->mpx_api, &data_request, eapol_pdu_data->mpx_user_id); + eapol_pdu_data->mpx_api->mpx_data_request(eapol_pdu_data->mpx_api, &data_request, eapol_pdu_data->mpx_user_id, MAC_DATA_NORMAL_PRIORITY); + return 0; +} + +int8_t ws_eapol_pdu_mpx_eui64_purge(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) +{ + eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr); + if (!eapol_pdu_data) { + return -1; + } + + eapol_pdu_data->mpx_api->mpx_eui64_purge(eapol_pdu_data->mpx_api, eui_64); + return 0; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.h index c385e9313c9..5c5320c0a8c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.h @@ -161,4 +161,16 @@ typedef int8_t ws_eapol_pdu_tx_status(protocol_interface_info_entry_t *interface */ int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer, ws_eapol_pdu_tx_status tx_status, uint8_t tx_identifier); +/** + * ws_eapol_pdu_mpx_eui64_purge purge EUI-64 from MPX + * + * \param interface_ptr interface + * \param eui_64 EUI-64 to purge + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_mpx_eui64_purge(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); + #endif /* WS_EAPOL_PDU_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c index 41e01be8f1d..2c2a6a3b93c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c @@ -189,6 +189,13 @@ static void ws_eapol_relay_socket_cb(void *cb) return; } + // EAPOL PDU data length is zero (message contains only supplicant EUI-64 and KMP ID) + if (cb_data->d_len == 9) { + ws_eapol_pdu_mpx_eui64_purge(eapol_relay->interface_ptr, socket_pdu); + ns_dyn_mem_free(socket_pdu); + return; + } + //First 8 byte is EUID64 and rsr payload if (ws_eapol_pdu_send_to_mpx(eapol_relay->interface_ptr, socket_pdu, socket_pdu + 8, cb_data->d_len - 8, socket_pdu, NULL, 0) < 0) { ns_dyn_mem_free(socket_pdu); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c index 17443e8469e..3f6279685d4 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c @@ -68,20 +68,41 @@ int ws_management_network_name_validate( return -1; } -int ws_management_phy_mode_id_set( +int ws_management_domain_configuration_set( int8_t interface_id, - uint8_t phy_mode_id) + uint8_t regulatory_domain, + uint8_t phy_mode_id, + uint8_t channel_plan_id) { + (void)regulatory_domain; (void)interface_id; (void)phy_mode_id; + (void)channel_plan_id; return -1; } -int ws_management_channel_plan_id_set( +int ws_management_domain_configuration_get( int8_t interface_id, + uint8_t *regulatory_domain, + uint8_t *phy_mode_id, + uint8_t *channel_plan_id) +{ + (void)regulatory_domain; + (void)interface_id; + (void)phy_mode_id; + (void)channel_plan_id; + return -1; +} + +int ws_management_domain_configuration_validate( + int8_t interface_id, + uint8_t regulatory_domain, + uint8_t phy_mode_id, uint8_t channel_plan_id) { + (void)regulatory_domain; (void)interface_id; + (void)phy_mode_id; (void)channel_plan_id; return -1; } @@ -431,6 +452,17 @@ int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) return -1; } +int ws_neighbor_info_get( + int8_t interface_id, + ws_neighbour_info_t *neighbor_ptr, + uint16_t count) +{ + (void) interface_id; + (void) neighbor_ptr; + (void) count; + return -1; +} + int ws_device_min_sens_set( int8_t interface_id, uint8_t device_min_sens) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c index 1f6f15abad6..c83f9b89b15 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c @@ -41,6 +41,7 @@ #include "Security/eapol/eapol_helper.h" #include "Service_Libs/etx/etx.h" #include "fhss_ws_extension.h" +#include "Service_Libs/random_early_detection/random_early_detection_api.h" #ifdef HAVE_WS @@ -90,6 +91,7 @@ typedef struct { uint8_t mpx_user_handle; /**< This MPX user defined handle */ ns_ie_iovec_t ie_vector_list[3]; /**< IE vectors: 1 for Header's, 1 for Payload and for MPX payload */ mcps_data_req_ie_list_t ie_ext; + mac_data_priority_t priority; ns_list_link_t link; /**< List link entry */ uint8_t ie_buffer[]; /**< Trailing buffer data */ } llc_message_t; @@ -109,6 +111,7 @@ typedef struct { ws_neighbor_temp_list_t active_eapol_temp_neigh; ws_neighbor_temp_list_t free_temp_neigh; llc_message_list_t llc_eap_pending_list; /**< Active Message list */ + uint16_t llc_eap_pending_list_size; /**< EAPOL active Message list size */ bool active_eapol_session: 1; /**< Indicating active EAPOL message */ } temp_entriest_t; @@ -117,6 +120,8 @@ typedef struct { #define ENHANCED_FRAME_RESPONSE (WH_IE_ELEMENT_HEADER_LENGTH + 2 + WH_IE_ELEMENT_HEADER_LENGTH + 4 + WH_IE_ELEMENT_HEADER_LENGTH + 1 + WH_IE_ELEMENT_HEADER_LENGTH + 5) typedef struct { + ns_list_link_t link; /**< List link entry */ + uint8_t mac_handle_base; /**< Mac handle id base this will be updated by 1 after use */ uint8_t llc_message_list_size; /**< llc_message_list list size */ uint16_t edfe_rx_wait_timer; @@ -131,9 +136,8 @@ typedef struct { ws_neighbor_info_request *ws_neighbor_info_request_cb; /**< LLC Neighbour discover API*/ uint8_t ws_enhanced_response_elements[ENHANCED_FRAME_RESPONSE]; ns_ie_iovec_t ws_header_vector; + bool high_priority_mode; protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ - - ns_list_link_t link; /**< List link entry */ } llc_data_base_t; static NS_LIST_DEFINE(llc_data_base_list, llc_data_base_t, link); @@ -159,7 +163,7 @@ static llc_data_base_t *ws_llc_base_allocate(void); static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t *data, const mcps_data_conf_payload_t *conf_data); static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext); static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id); -static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id); +static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id, mac_data_priority_t priority); static int8_t ws_llc_mpx_data_cb_register(const mpx_api_t *api, mpx_data_confirm *confirm_cb, mpx_data_indication *indication_cb, uint16_t user_id); static uint16_t ws_llc_mpx_header_size_get(const mpx_api_t *api, uint16_t user_id); static uint8_t ws_llc_mpx_data_purge_request(const mpx_api_t *api, struct mcps_purge_s *purge, uint16_t user_id); @@ -245,6 +249,7 @@ static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base) ns_list_remove(&llc_base->llc_message_list, message); ns_dyn_mem_free(message); llc_base->llc_message_list_size--; + random_early_detetction_aq_calc(llc_base->interface_ptr->llc_random_early_detection, llc_base->llc_message_list_size); } static void llc_message_id_allocate(llc_message_t *message, llc_data_base_t *llc_base, bool mpx_user) @@ -286,6 +291,7 @@ static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_bas } message->ack_requested = false; message->eapol_temporary = false; + message->priority = MAC_DATA_NORMAL_PRIORITY; return message; } @@ -534,10 +540,12 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * if (message) { //Start A pending EAPOL ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); + base->temp_entries->llc_eap_pending_list_size--; + random_early_detetction_aq_calc(base->interface_ptr->llc_eapol_random_early_detection, base->temp_entries->llc_eap_pending_list_size); ws_llc_mpx_eapol_send(base, message); } } else { - if (neighbor_info.ws_neighbor && neighbor_info.neighbor && neighbor_info.neighbor->link_lifetime <= WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME) { + if (neighbor_info.ws_neighbor && neighbor_info.neighbor && neighbor_info.neighbor->link_lifetime <= WS_NEIGHBOUR_TEMPORARY_NEIGH_MAX_LIFETIME) { //Remove temp neighbour tr_debug("Remove Temp Entry by TX confirm"); mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_info.neighbor); @@ -969,7 +977,7 @@ static void ws_llc_lowpan_mpx_header_set(llc_message_t *message, uint16_t user_i message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; } -static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data) +static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data, mac_data_priority_t priority) { wh_ie_sub_list_t ie_header_mask; memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); @@ -1020,6 +1028,8 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us //Add To active list llc_message_id_allocate(message, base, true); base->llc_message_list_size++; + message->priority = priority; + random_early_detetction_aq_calc(base->interface_ptr->llc_random_early_detection, base->llc_message_list_size); ns_list_add_to_end(&base->llc_message_list, message); mcps_data_req_t data_req; @@ -1097,7 +1107,7 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us message->ie_ext.payloadIovLength = 0; //Set Back 2 at response handler } - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL, message->priority); } static bool ws_llc_eapol_temp_entry_set(llc_data_base_t *base, const uint8_t *mac64) @@ -1147,15 +1157,16 @@ static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message) mcps_data_req_t data_req; llc_message_id_allocate(message, base, true); base->llc_message_list_size++; + random_early_detetction_aq_calc(base->interface_ptr->llc_random_early_detection, base->llc_message_list_size); ns_list_add_to_end(&base->llc_message_list, message); message->eapol_temporary = ws_llc_eapol_temp_entry_set(base, message->dst_address); ws_llc_eapol_data_req_init(&data_req, message); base->temp_entries->active_eapol_session = true; - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL, message->priority); } -static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data) +static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data, mac_data_priority_t priority) { wh_ie_sub_list_t ie_header_mask; memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); @@ -1190,6 +1201,7 @@ static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); return; } + message->priority = priority; message->mpx_user_handle = data->msduHandle; message->ack_requested = data->TxAckReq; @@ -1240,6 +1252,8 @@ static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, if (base->temp_entries->active_eapol_session) { //Move to pending list ns_list_add_to_end(&base->temp_entries->llc_eap_pending_list, message); + base->temp_entries->llc_eap_pending_list_size++; + random_early_detetction_aq_calc(base->interface_ptr->llc_eapol_random_early_detection, base->temp_entries->llc_eap_pending_list_size); } else { ws_llc_mpx_eapol_send(base, message); } @@ -1247,7 +1261,7 @@ static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, } -static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id) +static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id, mac_data_priority_t priority) { llc_data_base_t *base = ws_llc_discover_by_mpx(api); if (!base) { @@ -1270,12 +1284,21 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data } if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { - ws_llc_mpx_eapol_request(base, user_cb, data); + ws_llc_mpx_eapol_request(base, user_cb, data, priority); } else if (user_id == MPX_LOWPAN_ENC_USER_ID) { - ws_llc_lowpan_mpx_data_request(base, user_cb, data); + ws_llc_lowpan_mpx_data_request(base, user_cb, data, priority); } } +static void ws_llc_mpx_eui64_purge_request(const mpx_api_t *api, const uint8_t *eui64) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return; + } + tr_info("LLC purge EAPOL temporary entry: %s", tr_array(eui64, 8)); + ws_llc_release_eapol_temp_entry(base->temp_entries, eui64); +} static int8_t ws_llc_mpx_data_cb_register(const mpx_api_t *api, mpx_data_confirm *confirm_cb, mpx_data_indication *indication_cb, uint16_t user_id) { @@ -1325,6 +1348,15 @@ static uint8_t ws_llc_mpx_data_purge_request(const mpx_api_t *api, struct mcps_p return purge_status; } +static void wc_llc_mpx_priority_set_request(const mpx_api_t *api, bool enable_mode) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return; + } + base->high_priority_mode = enable_mode; +} + static void ws_llc_mpx_init(mpx_class_t *mpx_class) { //Init Mbed Class and API @@ -1334,6 +1366,8 @@ static void ws_llc_mpx_init(mpx_class_t *mpx_class) mpx_class->mpx_api.mpx_user_registration = &ws_llc_mpx_data_cb_register; mpx_class->mpx_api.mpx_data_request = &ws_llc_mpx_data_request; mpx_class->mpx_api.mpx_data_purge = &ws_llc_mpx_data_purge_request; + mpx_class->mpx_api.mpx_eui64_purge = &ws_llc_mpx_eui64_purge_request; + mpx_class->mpx_api.mpx_priority_mode_set = &wc_llc_mpx_priority_set_request; } static void ws_llc_clean(llc_data_base_t *base) @@ -1351,10 +1385,13 @@ static void ws_llc_clean(llc_data_base_t *base) ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); ns_dyn_mem_free(message); } + base->temp_entries->llc_eap_pending_list_size = 0; base->temp_entries->active_eapol_session = false; memset(&base->ie_params, 0, sizeof(llc_ie_params_t)); ws_llc_temp_neigh_info_table_reset(base->temp_entries); + //Disable High Priority mode + base->high_priority_mode = false; } static void ws_llc_temp_neigh_info_table_reset(temp_entriest_t *base) @@ -1657,6 +1694,11 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as return -1; } + if (base->high_priority_mode) { + //Drop asynch messages at High Priority mode + return -1; + } + //Calculate IE Buffer size request->wh_requested_ie_list.fc_ie = false; //Never should not be a part Asynch message @@ -1683,6 +1725,7 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as //Add To active list llc_message_id_allocate(message, base, false); base->llc_message_list_size++; + random_early_detetction_aq_calc(base->interface_ptr->llc_random_early_detection, base->llc_message_list_size); ns_list_add_to_end(&base->llc_message_list, message); message->messsage_type = request->message_type; @@ -1761,7 +1804,7 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as } } - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, &request->channel_list); + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, &request->channel_list, message->priority); return 0; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c index bdd2aadc9a5..d1bb845d8e0 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c @@ -156,12 +156,13 @@ int ws_management_network_name_validate( return 0; } -int ws_management_phy_mode_id_set( +int ws_management_domain_configuration_set( int8_t interface_id, - uint8_t phy_mode_id) + uint8_t regulatory_domain, + uint8_t phy_mode_id, + uint8_t channel_plan_id) { protocol_interface_info_entry_t *cur; - cur = protocol_stack_interface_info_get_by_id(interface_id); if (interface_id >= 0 && (!cur || !ws_info(cur))) { return -1; @@ -177,10 +178,22 @@ int ws_management_phy_mode_id_set( return -3; } - if (phy_mode_id != 255) { - cfg.phy_mode_id = phy_mode_id; - } else { + if (regulatory_domain == 255) { + cfg.regulatory_domain = cfg_default.regulatory_domain; + } else if (regulatory_domain != 0) { + cfg.regulatory_domain = regulatory_domain; + } + + if (phy_mode_id == 255) { cfg.phy_mode_id = cfg_default.phy_mode_id; + } else if (phy_mode_id != 0) { + cfg.phy_mode_id = phy_mode_id; + } + + if (channel_plan_id == 255) { + cfg.channel_plan_id = cfg_default.channel_plan_id; + } else if (channel_plan_id != 0) { + cfg.channel_plan_id = channel_plan_id; } if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) { @@ -190,34 +203,58 @@ int ws_management_phy_mode_id_set( return 0; } -int ws_management_channel_plan_id_set( +int ws_management_domain_configuration_get( int8_t interface_id, - uint8_t channel_plan_id) + uint8_t *regulatory_domain, + uint8_t *phy_mode_id, + uint8_t *channel_plan_id) { protocol_interface_info_entry_t *cur; - cur = protocol_stack_interface_info_get_by_id(interface_id); if (interface_id >= 0 && (!cur || !ws_info(cur))) { return -1; } ws_phy_cfg_t cfg; - ws_phy_cfg_t cfg_default; if (ws_cfg_phy_get(&cfg, NULL) < 0) { - return -3; + return -2; } - if (ws_cfg_phy_default_set(&cfg_default) < 0) { - return -3; + if (regulatory_domain) { + *regulatory_domain = cfg.regulatory_domain; + } + if (phy_mode_id) { + *phy_mode_id = cfg.phy_mode_id; + } + if (channel_plan_id) { + *channel_plan_id = cfg.channel_plan_id; } - if (channel_plan_id != 255) { - cfg.channel_plan_id = channel_plan_id; - } else { - cfg.channel_plan_id = cfg_default.channel_plan_id; + return 0; +} + +int ws_management_domain_configuration_validate( + int8_t interface_id, + uint8_t regulatory_domain, + uint8_t phy_mode_id, + uint8_t channel_plan_id) +{ + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (interface_id >= 0 && (!cur || !ws_info(cur))) { + return -1; } - if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) { + ws_phy_cfg_t cfg; + if (ws_cfg_phy_get(&cfg, NULL) < 0) { + return -3; + } + + cfg.regulatory_domain = regulatory_domain; + cfg.phy_mode_id = phy_mode_id; + cfg.channel_plan_id = channel_plan_id; + + if (ws_cfg_phy_validate(NULL, &cfg) < 0) { return -4; } @@ -890,7 +927,20 @@ int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) if (!cur || !ws_info(cur) || !info_ptr) { return -1; } - return ws_bootstrap_get_info(cur, info_ptr); + return ws_bootstrap_stack_info_get(cur, info_ptr); +} + +int ws_neighbor_info_get( + int8_t interface_id, + ws_neighbour_info_t *neighbor_ptr, + uint16_t count) +{ + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + return ws_bootstrap_neighbor_info_get(cur, neighbor_ptr, count); } int ws_device_min_sens_set( diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h index aa63fa181f8..516196abdf8 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h @@ -33,7 +33,6 @@ typedef struct ws_neighbor_class_entry { bool broadcast_timing_info_stored: 1; bool broadcast_shedule_info_stored: 1; bool synch_done : 1; - bool negative_aro_send : 1; bool unicast_data_rx : 1; } ws_neighbor_class_entry_t; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c index 47e73ace70b..452f3c5015d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c @@ -66,10 +66,8 @@ #define WAIT_FOR_AUTHENTICATION_TICKS 2 * 60 * 10 // 2 minutes // Wait after authentication has completed before supplicant entry goes inactive #define WAIT_AFTER_AUTHENTICATION_TICKS 15 * 10 // 15 seconds - -/* If EAP-TLS is delayed due to simultaneous negotiations limit, defines how - long to wait for previous negotiation to complete */ -#define EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT 60 * 10 // 60 seconds +// Waiting for authentication supplicant list maximum size +#define WAITING_SUPPLICANT_LIST_MAX_SIZE 50 // Default for maximum number of supplicants #define SUPPLICANT_MAX_NUMBER 5000 @@ -93,7 +91,9 @@ typedef struct { ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */ ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */ + ws_pae_auth_congestion_get *congestion_get; /**< Congestion get callback */ supp_list_t active_supp_list; /**< List of active supplicants */ + supp_list_t waiting_supp_list; /**< List of waiting supplicants */ shared_comp_list_t shared_comp_list; /**< Shared component list */ arm_event_storage_t *timer; /**< Timer */ sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */ @@ -101,6 +101,7 @@ typedef struct { sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */ sec_cfg_t *sec_cfg; /**< Security configuration */ uint16_t supp_max_number; /**< Max number of stored supplicants */ + uint16_t waiting_supp_list_size; /**< Waiting supplicants list size */ uint8_t relay_socked_msg_if_instance_id; /**< Relay socket message interface instance identifier */ uint8_t radius_socked_msg_if_instance_id; /**< Radius socket message interface instance identifier */ bool timer_running : 1; /**< Timer is running */ @@ -128,14 +129,17 @@ static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth); static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr); static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address); static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type); +static bool ws_pae_auth_active_limit_reached(uint16_t active_supp, pae_auth_t *pae_auth); static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size); static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result); 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 bool ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); +static bool 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(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, uint8_t socked_msg_if_instance_id, supp_entry_t *supp_entry, sec_cfg_t *sec_cfg); static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp); +static void ws_pae_auth_active_supp_deleted(void *pae_auth); +static void ws_pae_auth_waiting_supp_deleted(void *pae_auth); static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link); @@ -159,6 +163,7 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot pae_auth->pan_id = 0xffff; pae_auth->interface_ptr = interface_ptr; ws_pae_lib_supp_list_init(&pae_auth->active_supp_list); + ws_pae_lib_supp_list_init(&pae_auth->waiting_supp_list); ws_pae_lib_shared_comp_list_init(&pae_auth->shared_comp_list); pae_auth->timer = NULL; @@ -166,12 +171,16 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot pae_auth->nw_key_insert = NULL; pae_auth->nw_keys_remove = NULL; pae_auth->nw_key_index_set = NULL; + pae_auth->nw_info_updated = NULL; + pae_auth->ip_addr_get = NULL; + pae_auth->congestion_get = NULL; pae_auth->next_gtks = next_gtks; pae_auth->certs = certs; pae_auth->sec_keys_nw_info = sec_keys_nw_info; pae_auth->sec_cfg = sec_cfg; pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER; + pae_auth->waiting_supp_list_size = 0; pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; @@ -302,7 +311,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr) return 0; } -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get) +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get) { if (!interface_ptr) { return; @@ -318,6 +327,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ pae_auth->nw_key_index_set = nw_key_index_set; pae_auth->nw_info_updated = nw_info_updated; pae_auth->ip_addr_get = ip_addr_get; + pae_auth->congestion_get = congestion_get; } void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) @@ -394,8 +404,11 @@ int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_p return ret_value; } - // Checks if supplicant is active + // Checks if supplicant is active or waiting supp_entry_t *supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, eui_64); + if (!supp) { + supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->waiting_supp_list, eui_64); + } if (supp) { // Deletes keys and marks as revoked @@ -507,7 +520,8 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr) /* Purge in maximum five entries from supplicant list (starting from oldest one) per call to the function (called by nanostack monitor) */ - ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE); + ws_pae_lib_supp_list_purge(pae_auth, &pae_auth->active_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE, NULL); + ws_pae_lib_supp_list_purge(pae_auth, &pae_auth->waiting_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE, ws_pae_auth_waiting_supp_deleted); } int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated) @@ -608,6 +622,7 @@ static void ws_pae_auth_free(pae_auth_t *pae_auth) ws_pae_lib_shared_comp_list_free(&pae_auth->shared_comp_list); ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list); + ws_pae_lib_supp_list_delete(&pae_auth->waiting_supp_list); kmp_socket_if_unregister(pae_auth->kmp_service); @@ -690,8 +705,9 @@ void ws_pae_auth_fast_timer(uint16_t ticks) } // Updates KMP timers - bool running = ws_pae_lib_supp_list_timer_update(pae_auth, &pae_auth->active_supp_list, ticks, kmp_service_timer_if_timeout); - if (!running) { + bool active_running = ws_pae_lib_supp_list_timer_update(pae_auth, &pae_auth->active_supp_list, ticks, kmp_service_timer_if_timeout, ws_pae_auth_active_supp_deleted); + bool wait_running = ws_pae_lib_supp_list_timer_update(pae_auth, &pae_auth->waiting_supp_list, ticks, kmp_service_timer_if_timeout, ws_pae_auth_waiting_supp_deleted); + if (!active_running && !wait_running) { ws_pae_auth_timer_stop(pae_auth); } } @@ -936,6 +952,40 @@ static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_ap return ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type); } +static bool ws_pae_auth_active_limit_reached(uint16_t active_supp, pae_auth_t *pae_auth) +{ + return pae_auth->congestion_get(pae_auth->interface_ptr, active_supp); +} + +static supp_entry_t *ws_pae_auth_waiting_supp_list_add(pae_auth_t *pae_auth, supp_entry_t *supp_entry, const kmp_addr_t *addr) +{ + // Entry is already allocated + if (supp_entry) { + ns_list_add_to_start(&pae_auth->waiting_supp_list, supp_entry); + pae_auth->waiting_supp_list_size++; + } else { + // Create a new supplicant entry if not at limit + if (pae_auth->waiting_supp_list_size > WAITING_SUPPLICANT_LIST_MAX_SIZE) { + tr_info("PAE: waiting list full, eui-64: %s", trace_array(addr->eui_64, 8)); + return NULL; + } + supp_entry = ws_pae_lib_supp_list_add(&pae_auth->waiting_supp_list, addr); + if (!supp_entry) { + tr_info("PAE: waiting list no memory, eui-64: %s", trace_array(addr->eui_64, 8)); + return NULL; + } + pae_auth->waiting_supp_list_size++; + sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); + } + + // 90 percent of the EAPOL temporary entry lifetime (10 ticks per second) + supp_entry->waiting_ticks = pae_auth->sec_cfg->timing_cfg.temp_eapol_min_timeout * 900 / 100; + + tr_debug("PAE: to waiting, list size %i, retry %i, eui-64: %s", pae_auth->waiting_supp_list_size, supp_entry->waiting_ticks, trace_array(supp_entry->addr.eui_64, 8)); + + return supp_entry; +} + static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size) { pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); @@ -954,21 +1004,43 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t m supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr)); if (!supp_entry) { + uint16_t active_supp = ns_list_count(&pae_auth->active_supp_list); + + // Check if supplicant is already on the the waiting supplicant list + supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->waiting_supp_list, kmp_address_eui_64_get(addr)); + if (supp_entry) { + /* Remove from waiting list (supplicant is later added to active list, or if no room back to the start of the + * waiting list with updated timer) + */ + ns_list_remove(&pae_auth->waiting_supp_list, supp_entry); + pae_auth->waiting_supp_list_size--; + supp_entry->waiting_ticks = 0; + } else { + // Find supplicant from key storage + supp_entry = ws_pae_key_storage_supp_read(pae_auth, kmp_address_eui_64_get(addr), pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); + } + // Checks if active supplicant list has space for new supplicants - if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication)) { + if (ws_pae_auth_active_limit_reached(active_supp, pae_auth)) { tr_debug("PAE: active limit reached, eui-64: %s", trace_array(kmp_address_eui_64_get(addr), 8)); - return NULL; - } - // Find supplicant from key storage - supp_entry = ws_pae_key_storage_supp_read(pae_auth, kmp_address_eui_64_get(addr), pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); - if (supp_entry) { - // Move supplicant to active list - tr_debug("PAE: to active, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); - ns_list_add_to_start(&pae_auth->active_supp_list, supp_entry); + // If there is no space, add supplicant entry to the start of the waiting supplicant list + supp_entry = ws_pae_auth_waiting_supp_list_add(pae_auth, supp_entry, addr); + if (!supp_entry) { + return 0; + } + } else { + if (supp_entry) { + /* + * If there is space and there is already an allocated supplicant, add it to active list and + * start/continue authentication + */ + tr_debug("PAE: to active, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + ns_list_add_to_start(&pae_auth->active_supp_list, supp_entry); + } } } - // If does not exists add it to list + // If supplicant does not exists create a new supplicant entry to the active list if (!supp_entry) { supp_entry = ws_pae_lib_supp_list_add(&pae_auth->active_supp_list, addr); if (!supp_entry) { @@ -1044,35 +1116,37 @@ static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ kmp_api_create_response(kmp, KMP_RESULT_OK); } -static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys) +static bool ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys) { (void) sec_keys; // For now, just ignore if not ok if (result != KMP_RESULT_OK) { - return; + return false; } supp_entry_t *supp_entry = kmp_api_data_get(kmp); if (!supp_entry) { // Should not be possible - return; + return false; } kmp_service_t *service = kmp_api_service_get(kmp); pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); if (!pae_auth) { // Should not be possible - return; + return false; + } + + // Ensures that supplicant is in active supplicant list before initiating next KMP + if (!ws_pae_lib_supp_list_entry_is_in_list(&pae_auth->active_supp_list, supp_entry)) { + return false; } - ws_pae_auth_next_kmp_trigger(pae_auth, supp_entry); + return ws_pae_auth_next_kmp_trigger(pae_auth, supp_entry); } -static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry) +static bool ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry) { - // Disables KMP retry timer - 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(pae_auth, supp_entry); @@ -1080,7 +1154,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup // Supplicant goes inactive after 15 seconds ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_AFTER_AUTHENTICATION_TICKS); // All done - return; + return true; } else { kmp_api_t *api = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type); if (api != NULL) { @@ -1088,7 +1162,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup for GTK there can be previous terminating and the new one for next key index */ if (next_type != IEEE_802_11_GKH) { tr_info("KMP already ongoing; ignored, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); - return; + return false; } } } @@ -1096,25 +1170,10 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup // Increases waiting time for supplicant authentication ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS); - if (next_type == IEEE_802_1X_MKA || next_type == RADIUS_IEEE_802_1X_MKA) { - /* For EAP-TLS, limits the number of ongoing negotiations. If limit - is reached, authenticator does not initiate EAP-TLS right away. - If previous EAP-TLS negotiation completes before negotiation - trigger timeout, authenticator initiates EAP-TLS towards - supplicant. Otherwise supplicant must re-send initial EAPOL-Key - to try again using its trickle schedule */ - uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, next_type); - if (ongoing_eap_tls_cnt >= pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication) { - supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT; - tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(supp_entry->addr.eui_64, 8)); - return; - } - } - // Create new instance kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, pae_auth->relay_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg); if (!new_kmp) { - return; + return false; } // For radius EAP-TLS create also radius client in addition to EAP-TLS @@ -1122,12 +1181,12 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, RADIUS_CLIENT_PROT) != NULL) { // Radius client already exists, wait for it to be deleted ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); - return; + return false; } // Create radius client instance */ if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, RADIUS_CLIENT_PROT, pae_auth->radius_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg) == NULL) { ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); - return; + return false; } } // For EAP-TLS create also TLS client in addition to EAP-TLS @@ -1135,16 +1194,17 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, TLS_PROT) != NULL) { // TLS already exists, wait for it to be deleted ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); - return; + return false; } // Create TLS instance */ if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, pae_auth->relay_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg) == NULL) { ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); - return; + return false; } } kmp_api_create_request(new_kmp, next_type, &supp_entry->addr, &supp_entry->sec_keys); + return false; } static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry) @@ -1161,11 +1221,11 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry } else { next_type = IEEE_802_1X_MKA; } - tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + tr_info("PAE: start EAP-TLS, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } else if (sec_keys->ptk_mismatch) { // start 4WH towards supplicant next_type = IEEE_802_11_4WH; - tr_info("PAE start 4WH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + tr_info("PAE: start 4WH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } int8_t gtk_index = -1; @@ -1191,19 +1251,19 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry // 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)); + 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: 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)); + tr_info("PAE: update GTK index: %i, eui-64: %s", gtk_index, trace_array(supp_entry->addr.eui_64, 8)); } if (next_type == KMP_TYPE_NONE) { - tr_info("PAE authenticated, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + tr_info("PAE: authenticated, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } return next_type; @@ -1254,26 +1314,38 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp) return; } - pae_auth_t *pae_auth = NULL; - supp_entry_t *retry_supp = NULL; - // When EAP-TLS completes check if there are other supplicants that have requested it lately - if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA || kmp_api_type_get(kmp) == RADIUS_IEEE_802_1X_MKA) { - kmp_service_t *service = kmp_api_service_get(kmp); - pae_auth = ws_pae_auth_by_kmp_service_get(service); - if (pae_auth) { - retry_supp = ws_pae_lib_supp_list_entry_retry_timer_get(&pae_auth->active_supp_list); - } - } - // Delete KMP ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp); +} + +static void ws_pae_auth_active_supp_deleted(void *pae_auth_ptr) +{ + pae_auth_t *pae_auth = pae_auth_ptr; - if (retry_supp) { - tr_info("PAE next KMP trigger, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8)); + tr_info("Supplicant deleted"); + + uint16_t active_supp = ns_list_count(&pae_auth->active_supp_list); + if (ws_pae_auth_active_limit_reached(active_supp, pae_auth)) { + return; + } + + supp_entry_t *retry_supp = ns_list_get_first(&pae_auth->waiting_supp_list); + if (retry_supp != NULL) { + ns_list_remove(&pae_auth->waiting_supp_list, retry_supp); + pae_auth->waiting_supp_list_size--; + ns_list_add_to_start(&pae_auth->active_supp_list, retry_supp); + tr_info("PAE: waiting supplicant to active, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8)); + retry_supp->waiting_ticks = 0; ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp); } } +static void ws_pae_auth_waiting_supp_deleted(void *pae_auth_ptr) +{ + pae_auth_t *pae_auth = pae_auth_ptr; + pae_auth->waiting_supp_list_size--; +} + #endif /* HAVE_PAE_AUTH */ #endif /* HAVE_WS */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h index d302aeaf0f3..506ee4ee7bb 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.h @@ -249,6 +249,17 @@ typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interf */ typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); +/** + * ws_pae_auth_congestion_get get congestion information + * + * \param interface_ptr interface + * \param active_supp active supplicants + * + * \return TRUE reject, FALSE accept + * + */ +typedef bool ws_pae_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); + /** * ws_pae_auth_cb_register register PAE authenticator callbacks * @@ -258,9 +269,10 @@ typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ * \param nw_key_index_set network send key index callback * \param nw_info_updated network keys updated callback * \param ip_addr_get IP addressing information callback + * \param congestion_get congestion get callback * */ -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get); +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get); #else @@ -268,7 +280,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #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, nw_info_updated, ip_addr_get) {(void) hash_set;} +#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get) {(void) hash_set;} #define ws_pae_auth_start(interface_ptr) #define ws_pae_auth_gtks_updated NULL #define ws_pae_auth_nw_key_index_update NULL diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c index 57eb9a19c01..0f299ce55d6 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c @@ -88,6 +88,7 @@ typedef struct { ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */ ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */ ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */ + ws_pae_controller_congestion_get *congestion_get; /**< Congestion get callback */ ws_pae_controller_ip_addr_get *ip_addr_get; /**< IP address get callback */ ws_pae_delete *pae_delete; /**< PAE delete callback */ ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */ @@ -117,6 +118,7 @@ static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_key static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr); #ifdef HAVE_PAE_AUTH static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); +static bool ws_pae_controller_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); #endif static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry); @@ -139,8 +141,8 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters); static void ws_pae_controller_frame_counter_index_reset(frame_counters_t *frame_counters, uint8_t index); static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks); -static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, sec_prot_gtk_keys_t *gtks); -static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, sec_prot_gtk_keys_t *gtks); +static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); +static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME; @@ -238,7 +240,7 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit); } - ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get); + ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get, ws_pae_controller_auth_congestion_get); controller->auth_started = true; @@ -247,7 +249,7 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return 0; } -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated) +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated, ws_pae_controller_congestion_get *congestion_get) { if (!interface_ptr) { return -1; @@ -267,6 +269,7 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ controller->pan_ver_increment = pan_ver_increment; controller->nw_info_updated = nw_info_updated; controller->auth_next_target = auth_next_target; + controller->congestion_get = congestion_get; return 0; } @@ -368,7 +371,13 @@ static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entr } if (controller->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(controller->sec_keys_nw_info.gtks)) { - ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, controller->sec_keys_nw_info.gtks); + // Get own EUI-64 + uint8_t gtk_eui64[8] = {0}; + link_layer_address_s mac_params; + if (arm_nwk_mac_address_read(interface_ptr->id, &mac_params) >= 0) { + memcpy(gtk_eui64, mac_params.mac_long, 8); + } + ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, controller->sec_keys_nw_info.gtks); controller->sec_keys_nw_info.updated = false; sec_prot_keys_gtks_updated_reset(controller->sec_keys_nw_info.gtks); } @@ -388,6 +397,20 @@ static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t * controller->ip_addr_get(interface_ptr, address); } + +static bool ws_pae_controller_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp) +{ + if (!interface_ptr) { + return 0; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return 0; + } + + return controller->congestion_get(interface_ptr, active_supp); +} #endif int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) @@ -472,7 +495,6 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_ 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->sec_keys_nw_info.network_name); continue; @@ -675,6 +697,7 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) controller->pan_ver_increment = NULL; controller->nw_info_updated = NULL; controller->auth_next_target = NULL; + controller->congestion_get = NULL; memset(&controller->sec_cfg, 0, sizeof(sec_cfg_t)); @@ -685,7 +708,7 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) return 0; } -int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_ptr, struct ws_sec_timer_cfg_s *sec_timer_cfg, struct ws_sec_prot_cfg_s *sec_prot_cfg) +int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_ptr, struct ws_sec_timer_cfg_s *sec_timer_cfg, struct ws_sec_prot_cfg_s *sec_prot_cfg, struct ws_timing_cfg_s *timing_cfg) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); if (controller == NULL) { @@ -698,9 +721,6 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt controller->sec_cfg.prot_cfg.sec_prot_trickle_params.k = 0; controller->sec_cfg.prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp; controller->sec_cfg.prot_cfg.sec_prot_retry_timeout = sec_prot_cfg->sec_prot_retry_timeout * 10; - - controller->sec_cfg.prot_cfg.sec_max_ongoing_authentication = sec_prot_cfg->sec_max_ongoing_authentication; - controller->sec_cfg.prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay; controller->sec_cfg.prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin; controller->sec_cfg.prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax; @@ -715,6 +735,10 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt controller->sec_cfg.radius_cfg = pae_controller_config.radius_cfg; + if (timing_cfg) { + controller->sec_cfg.timing_cfg.temp_eapol_min_timeout = timing_cfg->temp_eapol_min_timeout; + } + return 0; } @@ -826,32 +850,46 @@ static void ws_pae_controller_frame_counter_index_reset(frame_counters_t *frame_ static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks) { - if (ws_pae_controller_nvm_nw_info_read(controller->interface_ptr, &controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtks) < 0) { + uint8_t nvm_gtk_eui64[8]; + if (ws_pae_controller_nvm_nw_info_read(controller->interface_ptr, &controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, nvm_gtk_eui64, gtks) < 0) { // If no stored GTKs and network info (pan_id and network name) exits return -1; } + /* Get own EUI-64 and compare to the one read from the NVM. In case of mismatch delete GTKs and make + full authentication to update keys with new EUI-64 and in case of authenticator to update new + authenticator EUI-64 to the network. */ + uint8_t gtk_eui64[8] = {0}; + link_layer_address_s mac_params; + if (arm_nwk_mac_address_read(controller->interface_ptr->id, &mac_params) >= 0) { + memcpy(gtk_eui64, mac_params.mac_long, 8); + } + if (memcmp(nvm_gtk_eui64, gtk_eui64, 8) != 0) { + tr_warn("NVM EUI-64 mismatch, current: %s stored: %s", tr_array(gtk_eui64, 8), tr_array(nvm_gtk_eui64, 8)); + sec_prot_keys_gtks_clear(gtks); + } + // Sets also new pan_id used for pan_id set by bootstrap controller->sec_keys_nw_info.new_pan_id = controller->sec_keys_nw_info.key_pan_id; return 0; } -static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, sec_prot_gtk_keys_t *gtks) +static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) { nw_info_nvm_tlv_t *tlv = (nw_info_nvm_tlv_t *) ws_pae_controller_nvm_tlv_get(interface_ptr); if (!tlv) { return -1; } - ws_pae_nvm_store_nw_info_tlv_create(tlv, pan_id, network_name, gtks); + ws_pae_nvm_store_nw_info_tlv_create(tlv, pan_id, network_name, gtk_eui64, gtks); ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, (nvm_tlv_t *) tlv); return 0; } -static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, sec_prot_gtk_keys_t *gtks) +static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) { nw_info_nvm_tlv_t *tlv_entry = (nw_info_nvm_tlv_t *) ws_pae_controller_nvm_tlv_get(interface_ptr); if (!tlv_entry) { @@ -864,7 +902,7 @@ static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t return -1; } - if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtks) < 0) { + if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtk_eui64, gtks) < 0) { return -1; } @@ -946,7 +984,8 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt } if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) { // Key material invalid or GTKs are expired, delete GTKs from NVM - ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, NULL); + uint8_t gtk_eui64[8] = {0}; // Set GTK EUI-64 to zero + ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, NULL); } } @@ -1232,7 +1271,7 @@ int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t * return 0; } - if (ws_pae_controller_configure(controller->interface_ptr, NULL, NULL) < 0) { + if (ws_pae_controller_configure(controller->interface_ptr, NULL, NULL, NULL) < 0) { return -1; } @@ -1282,7 +1321,7 @@ int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uin pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); if (controller) { - ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL, NULL); } return 0; @@ -1335,7 +1374,7 @@ int8_t ws_pae_controller_radius_timing_set(int8_t interface_id, bbr_radius_timin pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); if (controller) { - ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL, NULL); } return 0; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h index 2b619ccf922..516a6cf22d3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h @@ -23,7 +23,7 @@ typedef enum { AUTH_RESULT_OK = 0, // Successful AUTH_RESULT_ERR_NO_MEM = -1, // No memory - AUTH_RESULT_ERR_TX_NO_ACK = -2, // No acknowledge was received + AUTH_RESULT_ERR_TX_ERR = -2, // TX error (e.g. no acknowledge was received) AUTH_RESULT_ERR_UNSPEC = -3 // Other reason } auth_result_e; @@ -31,6 +31,7 @@ struct nvm_tlv_entry; struct ws_sec_timer_cfg_s; struct ws_sec_prot_cfg_s; struct bbr_radius_timing; +struct ws_timing_cfg_s; /** * ws_pae_controller_set_target sets EAPOL target for PAE supplicant @@ -98,12 +99,13 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr); * \param interface_ptr interface * \param sec_timer_cfg timer configuration or NULL if not set * \param sec_prot_cfg protocol configuration or NULL if not set + * \param timing_cfg timing configuration or NULL if not set * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_ptr, struct ws_sec_timer_cfg_s *sec_timer_cfg, struct ws_sec_prot_cfg_s *sec_prot_cfg); +int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_ptr, struct ws_sec_timer_cfg_s *sec_timer_cfg, struct ws_sec_prot_cfg_s *sec_prot_cfg, struct ws_timing_cfg_s *timing_cfg); /** * ws_pae_controller_init initializes PAE supplicant @@ -612,6 +614,17 @@ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t */ typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); +/** + * ws_pae_controller_congestion_get get congestion information + * + * \param interface_ptr interface + * \param active_supp active supplicants + * + * \return TRUE reject, FALSE accept + * + */ +typedef bool ws_pae_controller_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); + /** * ws_pae_controller_cb_register register controller callbacks * @@ -625,12 +638,13 @@ typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t * * \param nw_frame_counter_read network frame counter read callback * \param pan_ver_increment PAN version increment callback * \param nw_info_updated network information updated callback + * \param congestion_get congestion get callback * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated); +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated, ws_pae_controller_congestion_get *congestion_get); /** * ws_pae_controller_ip_addr_get gets IP addressing information @@ -701,7 +715,7 @@ void ws_pae_controller_forced_gc(bool full_gc); #define ws_pae_controller_stop(interface_ptr) #define ws_pae_controller_delete(interface_ptr) -#define ws_pae_controller_cb_register(interface_ptr, completed, nw_key_set, nw_key_clear, nw_send_key_index_set, pan_ver_increment) 1 +#define ws_pae_controller_cb_register(interface_ptr, completed, nw_key_set, nw_key_clear, nw_send_key_index_set, pan_ver_increment, congestion_get) 1 #define ws_pae_controller_nvm_tlv_get(interface_ptr) NULL #define ws_pae_controller_forced_gc NULL diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c index 3f9ab10b37f..fb635e7741e 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c @@ -193,18 +193,23 @@ supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t entry->addr.type = KMP_ADDR_EUI_64_AND_IP; kmp_address_copy(&entry->addr, addr); - ns_list_add_to_end(supp_list, entry); + ns_list_add_to_start(supp_list, entry); return entry; } -int8_t ws_pae_lib_supp_list_remove(supp_list_t *supp_list, supp_entry_t *supp) +int8_t ws_pae_lib_supp_list_remove(void *instance, supp_list_t *supp_list, supp_entry_t *supp, ws_pae_lib_supp_deleted supp_deleted) { ns_list_remove(supp_list, supp); ws_pae_lib_supp_delete(supp); ns_dyn_mem_free(supp); + + if (supp_deleted != NULL) { + supp_deleted(instance); + } + return 0; } @@ -222,11 +227,11 @@ supp_entry_t *ws_pae_lib_supp_list_entry_eui_64_get(const supp_list_t *supp_list void ws_pae_lib_supp_list_delete(supp_list_t *supp_list) { ns_list_foreach_safe(supp_entry_t, entry, supp_list) { - ws_pae_lib_supp_list_remove(supp_list, entry); + ws_pae_lib_supp_list_remove(NULL, supp_list, entry, NULL); } } -bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout, ws_pae_lib_supp_deleted supp_deleted) { bool timer_running = false; @@ -235,7 +240,7 @@ bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_ if (running) { timer_running = true; } else { - ws_pae_lib_supp_list_to_inactive(instance, active_supp_list, entry); + ws_pae_lib_supp_list_to_inactive(instance, active_supp_list, entry, supp_deleted); } } @@ -260,7 +265,7 @@ void ws_pae_lib_supp_init(supp_entry_t *entry) memset(&entry->addr, 0, sizeof(kmp_addr_t)); memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t)); entry->ticks = 0; - entry->retry_ticks = 0; + entry->waiting_ticks = 0; entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000; entry->active = true; entry->access_revoked = false; @@ -283,18 +288,18 @@ bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t entry->ticks -= ticks; } else { entry->ticks = 0; - entry->retry_ticks = 0; } } // Updates retry timer - if (entry->retry_ticks > ticks) { - entry->retry_ticks -= ticks; + if (entry->waiting_ticks > ticks) { + keep_timer_running = true; + entry->waiting_ticks -= ticks; } else { - if (entry->retry_ticks > 0) { - tr_info("EAP-TLS max ongoing delay timeout eui-64: %s", trace_array(entry->addr.eui_64, 8)); + if (entry->waiting_ticks > 0) { + tr_info("Waiting supplicant timeout eui-64: %s", trace_array(entry->addr.eui_64, 8)); } - entry->retry_ticks = 0; + entry->waiting_ticks = 0; } if (!instance) { @@ -350,7 +355,7 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * entry->addr.type = KMP_ADDR_EUI_64_AND_IP; } -void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry) +void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry, ws_pae_lib_supp_deleted supp_deleted) { if (!entry->active) { return; @@ -360,7 +365,7 @@ void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_l if (entry->access_revoked) { tr_info("Access revoked; deleted, eui-64: %s", trace_array(entry->addr.eui_64, 8)); - ws_pae_lib_supp_list_remove(active_supp_list, entry); + ws_pae_lib_supp_list_remove(instance, active_supp_list, entry, supp_deleted); return; } @@ -368,10 +373,13 @@ void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_l ws_pae_key_storage_supp_write(instance, entry); // Remove supplicant entry - ws_pae_lib_supp_list_remove(active_supp_list, entry); + ws_pae_lib_supp_list_remove(instance, active_supp_list, entry, supp_deleted); + if (supp_deleted) { + supp_deleted(instance); + } } -void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge) +void ws_pae_lib_supp_list_purge(void *instance, supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge, ws_pae_lib_supp_deleted supp_deleted) { uint16_t active_supp = ns_list_count(active_supp_list); @@ -385,7 +393,7 @@ void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_numb ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) { if (remove_count > 0 && ws_pae_lib_kmp_list_empty(&entry->kmp_list)) { tr_info("Active supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8)); - ws_pae_lib_supp_list_remove(active_supp_list, entry); + ws_pae_lib_supp_list_remove(instance, active_supp_list, entry, supp_deleted); remove_count--; } else { break; @@ -394,16 +402,6 @@ void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_numb } } -bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number) -{ - uint16_t active_supp = ns_list_count(active_supp_list); - if (active_supp > max_number) { - return true; - } - - return false; -} - uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type) { uint16_t kmp_count = 0; @@ -419,33 +417,28 @@ uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type) return kmp_count; } -kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size) +bool ws_pae_lib_supp_list_entry_is_in_list(supp_list_t *supp_list, supp_entry_t *searched_entry) { ns_list_foreach(supp_entry_t, entry, supp_list) { - ns_list_foreach(kmp_entry_t, kmp_entry, &entry->kmp_list) { - if (kmp_api_receive_check(kmp_entry->kmp, pdu, size)) { - return kmp_entry->kmp; - } + if (entry == searched_entry) { + return true; } } - return NULL; + return false; } -supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list) +kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size) { - supp_entry_t *retry_supp = NULL; - ns_list_foreach(supp_entry_t, entry, supp_list) { - // Finds entry with shortest timeout i.e. oldest one - if (entry->retry_ticks > 0) { - if (!retry_supp || retry_supp->retry_ticks > entry->retry_ticks) { - retry_supp = entry; + ns_list_foreach(kmp_entry_t, kmp_entry, &entry->kmp_list) { + if (kmp_api_receive_check(kmp_entry->kmp, pdu, size)) { + return kmp_entry->kmp; } } } - return retry_supp; + return NULL; } int8_t ws_pae_lib_shared_comp_list_init(shared_comp_list_t *comp_list) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h index dc9a0b67b56..e29ef5bd0f2 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h @@ -36,7 +36,7 @@ typedef struct supp_entry_s { kmp_addr_t addr; /**< EUI-64 (Relay IP address, Relay port) */ sec_prot_keys_t sec_keys; /**< Security keys */ uint32_t ticks; /**< Ticks */ - uint16_t retry_ticks; /**< Retry ticks */ + uint16_t waiting_ticks; /**< Waiting ticks */ uint16_t store_ticks; /**< NVM store ticks */ bool active : 1; /**< Is active */ bool access_revoked : 1; /**< Nodes access is revoked */ @@ -211,16 +211,26 @@ void ws_pae_lib_supp_list_init(supp_list_t *supp_list); */ supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t *addr); +/** + * ws_pae_lib_supp_deleted supplicant delete callback + * + * \param instance Instance + * + */ +typedef void ws_pae_lib_supp_deleted(void *instance); + /** * ws_pae_lib_supp_list_add removes entry from supplicant list * + * \param instance Instance * \param supp_list supplicant list * \param entry entry + * \param supp_deleted callback to call on supplicant delete * * \return < 0 failure * \return >= 0 success */ -int8_t ws_pae_lib_supp_list_remove(supp_list_t *supp_list, supp_entry_t *entry); +int8_t ws_pae_lib_supp_list_remove(void *instance, supp_list_t *supp_list, supp_entry_t *supp, ws_pae_lib_supp_deleted supp_deleted); /** * ws_pae_lib_supp_list_entry_eui_64_get gets entry from supplicant list based on EUI-64 @@ -249,11 +259,12 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list); * \param inactive_supp_list list of inactive supplicants * \param ticks timer ticks * \param timeout callback to call on timeout + * \param supp_deleted callback to call on supplicant delete * * \return true timer needs still to be running * \return false timer can be stopped */ -bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); +bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout, ws_pae_lib_supp_deleted supp_deleted); /** * ws_pae_lib_supp_list_slow_timer_update updates slow timer on supplicant list @@ -336,31 +347,23 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * * \param instance Instance * \param active_supp_list list of active supplicants * \param entry supplicant entry + * \param supp_deleted callback to call on supplicant delete * */ -void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry); +void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry, ws_pae_lib_supp_deleted supp_deleted); /** * ws_pae_lib_supp_list_purge purge inactive supplicants list * + * \param instance Instance * \param active_supp_list list of active supplicants * \param max_number maximum number of supplicant entries, can be set to 0 in combination with max_purge * to free list entries even when maximum number supplicant entries has not been reached * \param max_purge maximum number of supplicants to purge in one call, 0 means not limited + * \param supp_deleted callback to call on supplicant delete * */ -void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge); - -/** - * ws_pae_lib_supp_list_limit_reached_check check if active supplicant list limit has been reached - * - * \param active_supp_list list of active supplicants - * \param max_number maximum number of supplicant entries - * - * \return true limit has been reached - * \return false limit has not been reached - */ -bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number); +void ws_pae_lib_supp_list_purge(void *instance, supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge, ws_pae_lib_supp_deleted supp_deleted); /** * ws_pae_lib_supp_list_kmp_count counts the number of KMPs of a certain type in a list of supplicants @@ -374,26 +377,27 @@ bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, ui uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type); /** - * ws_pae_lib_supp_list_kmp_receive_check check if received message is for this KMP in a list of supplicants + * ws_pae_lib_supp_list_entry_is_in_list checks if the entry is in the list * * \param supp_list list of supplicants - * \param pdu pdu - * \param size pdu size + * \param searched_entry entry that is searched * - * \return KMP api for the received message + * \return TRUE entry is in list, FALSE otherwise * */ -kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size); +bool ws_pae_lib_supp_list_entry_is_in_list(supp_list_t *supp_list, supp_entry_t *searched_entry); /** - * ws_pae_lib_supp_list_entry_retry_timer_get checks if some supplicant has retry timer running + * ws_pae_lib_supp_list_kmp_receive_check check if received message is for this KMP in a list of supplicants * * \param supp_list list of supplicants + * \param pdu pdu + * \param size pdu size * - * \return supplicant with retry timer running or NULL if no supplicants with timer running + * \return KMP api for the received message * */ -supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list); +kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size); /** * ws_pae_lib_shared_comp_list_init init shared component list diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c index fa26ab3f5c5..ba575c2acb0 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -67,7 +67,7 @@ void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry) ns_dyn_mem_free(tlv_entry); } -void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) { int len; tlv_entry->tag = PAE_NVM_NW_INFO_TAG; @@ -87,6 +87,9 @@ void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t memcpy((char *)tlv, nw_name, len); tlv += 33; + memcpy((char *)tlv, gtk_eui64, 8); + tlv += 8; + uint64_t current_time = ws_pae_current_time_get(); for (uint8_t i = 0; i < GTK_NUM; i++) { @@ -119,7 +122,7 @@ void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t } -int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) { if (!tlv_entry || !pan_id || !nw_name) { return -1; @@ -144,6 +147,9 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t } tlv += 33; + memcpy(gtk_eui64, (char *)tlv, 8); + tlv += 8; + uint64_t current_time = ws_pae_current_time_get(); tr_debug("NVM NW_INFO current time: %"PRIi64, current_time); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.h index 23f164d4d8e..3d6e6432312 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -35,8 +35,8 @@ #define PAE_NVM_KEY_STORAGE_INDEX_TAG 4 #define PAE_NVM_KEY_STORAGE_TAG 5 -// pan_id (2) + network name (33) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4 -#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 8 + 1 + 1 + GTK_LEN) * GTK_NUM +// pan_id (2) + network name (33) + GTK EUI-64 (own EUI-64) (8) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4 +#define PAE_NVM_NW_INFO_LEN 2 + 33 + 8 + (1 + 8 + 1 + 1 + GTK_LEN) * GTK_NUM // PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK lifetime (4) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK lifetime (4) + PTK (48) #define PAE_NVM_KEYS_LEN 1 + 8 + 1 + 4 + PMK_LEN + 8 + 1 + 4 + PTK_LEN @@ -95,7 +95,7 @@ void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry); * \return TLV entry or NULL * */ -void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV @@ -109,7 +109,7 @@ void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t * \return >= 0 success * */ -int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_keys_tlv_create create NVM keys TLV diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c index d3dc8a0220b..d73de75a2be 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_supp.c @@ -151,7 +151,7 @@ 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); -static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); +static bool ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp); @@ -429,11 +429,7 @@ static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_ pae_supp->auth_trickle_running = false; if (pae_supp->auth_requested && pae_supp->auth_completed) { pae_supp->auth_requested = false; - uint8_t *target_eui_64 = NULL; - if (result != AUTH_RESULT_OK) { - target_eui_64 = pae_supp->target_addr.eui_64; - } - pae_supp->auth_completed(pae_supp->interface_ptr, result, target_eui_64); + pae_supp->auth_completed(pae_supp->interface_ptr, result, pae_supp->target_addr.eui_64); } } @@ -841,7 +837,7 @@ void ws_pae_supp_slow_timer(uint16_t seconds) } auth_result_e result = AUTH_RESULT_ERR_UNSPEC; if (pae_supp->tx_failure_on_initial_key) { - result = AUTH_RESULT_ERR_TX_NO_ACK; + result = AUTH_RESULT_ERR_TX_ERR; pae_supp->tx_failure_on_initial_key = false; } ws_pae_supp_authenticate_response(pae_supp, result); @@ -1226,12 +1222,12 @@ static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ kmp_api_create_response(kmp, KMP_RESULT_OK); } -static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys) +static bool ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys) { 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; + return false; } kmp_type_e type = kmp_api_type_get(kmp); @@ -1254,7 +1250,7 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e /* If initial EAPOL-key message sending fails to tx no acknowledge, indicates failure so that bootstrap can decide if EAPOL target should be changed */ - else if (type > IEEE_802_1X_INITIAL_KEY && result == KMP_RESULT_ERR_TX_NO_ACK) { + else if (type > IEEE_802_1X_INITIAL_KEY && (result == KMP_RESULT_ERR_TX_NO_ACK || result == KMP_RESULT_ERR_TX_UNSPEC)) { tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8)); /* Fails authentication only if other authentication protocols are not yet started by authenticator */ @@ -1263,6 +1259,8 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e pae_supp->tx_failure_on_initial_key = true; } } + + return false; } static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.c index 85f25112213..a6e794e4b54 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.c @@ -51,20 +51,69 @@ int ws_statistics_stop(int8_t interface_id) void ws_stats_update(protocol_interface_info_entry_t *cur, ws_stats_type_t type, uint32_t update_val) { - if (!cur || !ws_info(cur)) { + if (!cur || !ws_info(cur) || !cur->ws_info->stored_stats_ptr) { return; } ws_statistics_t *stored_stats = cur->ws_info->stored_stats_ptr; - if (stored_stats) { - switch (type) { - case STATS_WS_ASYNCH_TX: - stored_stats->asynch_tx_count += update_val; - break; - case STATS_WS_ASYNCH_RX: - stored_stats->asynch_rx_count += update_val; - break; - } + switch (type) { + case STATS_WS_ASYNCH_TX: + stored_stats->asynch_tx_count += update_val; + break; + case STATS_WS_ASYNCH_RX: + stored_stats->asynch_rx_count += update_val; + break; + case STATS_WS_ASYNCH_TX_PAS: + stored_stats->sent_PAS += update_val; + break; + case STATS_WS_ASYNCH_TX_PA: + stored_stats->sent_PA += update_val; + break; + case STATS_WS_ASYNCH_TX_PCS: + stored_stats->sent_PCS += update_val; + break; + case STATS_WS_ASYNCH_TX_PC: + stored_stats->sent_PC += update_val; + break; + case STATS_WS_ASYNCH_RX_PAS: + stored_stats->recv_PAS += update_val; + break; + case STATS_WS_ASYNCH_RX_PA: + stored_stats->recv_PA += update_val; + break; + case STATS_WS_ASYNCH_RX_PCS: + stored_stats->recv_PCS += update_val; + break; + case STATS_WS_ASYNCH_RX_PC: + stored_stats->recv_PC += update_val; + break; + case STATS_WS_STATE_1: + stored_stats->join_state_1 += update_val; + break; + case STATS_WS_STATE_2: + stored_stats->join_state_2 += update_val; + break; + case STATS_WS_STATE_3: + stored_stats->join_state_3 += update_val; + break; + case STATS_WS_STATE_4: + stored_stats->join_state_4 += update_val; + break; + case STATS_WS_STATE_5: + stored_stats->join_state_5 += update_val; + break; + case STATS_WS_NEIGHBOUR_ADD: + stored_stats->Neighbour_add += update_val; + break; + case STATS_WS_NEIGHBOUR_REMOVE: + stored_stats->Neighbour_remove += update_val; + break; + case STATS_WS_CHILD_ADD: + stored_stats->Child_add += update_val; + break; + case STATS_WS_CHILD_REMOVE: + stored_stats->child_remove += update_val; + break; } } #endif // HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.h index 8f7776d97d5..5a315556f88 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_stats.h @@ -22,7 +22,24 @@ typedef enum { STATS_WS_ASYNCH_TX, - STATS_WS_ASYNCH_RX + STATS_WS_ASYNCH_RX, + STATS_WS_ASYNCH_RX_PAS, + STATS_WS_ASYNCH_RX_PA, + STATS_WS_ASYNCH_RX_PCS, + STATS_WS_ASYNCH_RX_PC, + STATS_WS_ASYNCH_TX_PAS, + STATS_WS_ASYNCH_TX_PA, + STATS_WS_ASYNCH_TX_PCS, + STATS_WS_ASYNCH_TX_PC, + STATS_WS_STATE_1, + STATS_WS_STATE_2, + STATS_WS_STATE_3, + STATS_WS_STATE_4, + STATS_WS_STATE_5, + STATS_WS_NEIGHBOUR_ADD, + STATS_WS_NEIGHBOUR_REMOVE, + STATS_WS_CHILD_ADD, + STATS_WS_CHILD_REMOVE, } ws_stats_type_t; void ws_stats_update(protocol_interface_info_entry_t *cur, ws_stats_type_t type, uint32_t update_val); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c b/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c index 8ccf5cb4a87..045e6c471c3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.c @@ -212,10 +212,12 @@ buffer_routing_info_t *ipv6_buffer_route_to(buffer_t *buf, const uint8_t *next_h * reduce an existing entry if route has changed) */ if (dest_entry->pmtu > outgoing_if->ipv6_neighbour_cache.link_mtu) { dest_entry->pmtu = outgoing_if->ipv6_neighbour_cache.link_mtu; + dest_entry->pmtu_lifetime = outgoing_if->pmtu_lifetime; } /* Route can also limit PMTU */ if (dest_entry->pmtu > route->route_info.pmtu) { dest_entry->pmtu = route->route_info.pmtu; + dest_entry->pmtu_lifetime = outgoing_if->pmtu_lifetime; } /* Buffer then gets this PMTU (overwriting what we wrote from the route) */ route->route_info.pmtu = dest_entry->pmtu; @@ -613,6 +615,16 @@ buffer_t *ipv6_forwarding_down(buffer_t *buf) /* Routing code may say it needs to tunnel to add headers - loop back to IP layer if requested */ if (exthdr_result == IPV6_EXTHDR_MODIFY_TUNNEL) { + + if (buffer_data_length(buf) > IPV6_MIN_LINK_MTU) { + /* recover IP addresses that icmpv6_error needs, which routing code will have overwritten */ + buf->src_sa.addr_type = ADDR_IPV6; + memcpy(buf->src_sa.address, buffer_data_pointer(buf) + IPV6_HDROFF_SRC_ADDR, 16); + buf->dst_sa.addr_type = ADDR_IPV6; + memcpy(buf->dst_sa.address, buffer_data_pointer(buf) + IPV6_HDROFF_DST_ADDR, 16); + return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_PACKET_TOO_BIG, 0, IPV6_MIN_LINK_MTU); + } + /* Avoid an infinite loop in the event of routing code failure - never * let them ask for tunnelling more than once. */ @@ -623,6 +635,7 @@ buffer_t *ipv6_forwarding_down(buffer_t *buf) buf->options.tunnelled = true; buf->options.ip_extflags = 0; + buf->options.ipv6_use_min_mtu = -1; /* Provide tunnel source, unless already set */ if (buf->src_sa.addr_type == ADDR_NONE) { @@ -1003,7 +1016,7 @@ static buffer_t *ipv6_consider_forwarding_unicast_packet(buffer_t *buf, protocol /* route_info.pmtu will cover limits from both the interface and the * route. As a bonus, it will also cover any PMTUD we happen to have done - * to that destination ourselves, as well as mop up any tunnelling issues. + * to that destination ourselves. Extra limits due to tunnelling are checked on tunnel entry in ipv6_down. */ if (routing->route_info.pmtu < buffer_data_length(buf)) { buf->interface = cur; @@ -1349,6 +1362,9 @@ buffer_t *ipv6_forwarding_up(buffer_t *buf) } } else { /* unicast */ if (!for_us) { + if (cur->if_common_forwarding_out_cb) { + cur->if_common_forwarding_out_cb(cur, buf); + } return ipv6_consider_forwarding_unicast_packet(buf, cur, &ll_src); } } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.h b/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.h index 3a60c224dfc..0927891c594 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/ipv6.h @@ -57,7 +57,7 @@ typedef enum ipv6_exthdr_stage { * If it needs to insert headers that are not present, it can force insertion * into a tunnel, by: * setting dst_sa and src_sa appropriate for the tunnel endpoints - * XXX does this work out okay with dest cache and PMTU? + * src_sa.addr_type can be set to ADDR_NONE to auto-select tunnel source address * updating route info like next hop if necessary (probably not) * returning IPV6_EXTHDR_MODIFY_TUNNEL * During new header formation for the tunnel, IPV6_EXTHDR_INSERT will be diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_monitor.h b/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_monitor.h index 2d98feb2def..867cff47fcd 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_monitor.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_monitor.h @@ -33,9 +33,9 @@ int ns_monitor_clear(void); void ns_monitor_timer(uint16_t seconds); -int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical); +int ns_monitor_heap_gc_threshold_set(uint32_t high_min, uint32_t high_max, uint8_t high_percentage, uint32_t critical_min, uint32_t critical_max, uint8_t critical_percentage); -int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage); +int ns_monitor_packet_ingress_rate_limit_by_memory(uint32_t minimum_required, uint32_t Maximum_allowed, uint8_t free_heap_percentage); bool ns_monitor_packet_allocation_allowed(void); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h b/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h index 23ec4db7eca..4af22a42498 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h @@ -52,6 +52,10 @@ #define SOCKET_DEFAULT_STREAM_SNDLOWAT 512 #endif +#ifndef SOCKET_DEFAULT_REFERENCE_LIMIT +#define SOCKET_DEFAULT_REFERENCE_LIMIT 512 +#endif + typedef enum socket_family_e { SOCKET_FAMILY_NONE, SOCKET_FAMILY_IPV6, diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_monitor.c b/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_monitor.c index 22d4c43e50f..83c4d3512c3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_monitor.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_monitor.c @@ -63,7 +63,7 @@ typedef struct ns_monitor__s { static ns_monitor_t *ns_monitor_ptr = NULL; -static uint8_t ns_dyn_mem_rate_limiting_threshold_percentage = 0; // Percentage of free memory required to allow routing +static ns_mem_heap_size_t ns_dyn_mem_rate_limiting_threshold = 0; // amount of free memory required to allow routing 0 = disabled typedef void (ns_maintenance_gc_cb)(bool full_gc); @@ -176,32 +176,75 @@ int ns_monitor_clear(void) return -1; } -int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical) +int ns_monitor_heap_gc_threshold_set(uint32_t high_min, uint32_t high_max, uint8_t high_percentage, uint32_t critical_min, uint32_t critical_max, uint8_t critical_percentage) { - if (ns_monitor_ptr && (percentage_critical <= 100) && (percentage_high < percentage_critical)) { + if (ns_monitor_ptr && (critical_percentage <= 100) && (high_percentage < critical_percentage)) { ns_monitor_ptr->heap_high_watermark = SET_WATERMARK( ns_monitor_ptr->mem_stats->heap_sector_size, - percentage_high + high_percentage ); + if (ns_monitor_ptr->mem_stats->heap_sector_size - ns_monitor_ptr->heap_high_watermark < high_min) { + ns_monitor_ptr->heap_high_watermark = ns_monitor_ptr->mem_stats->heap_sector_size - high_min; + } + + if (high_max && ns_monitor_ptr->mem_stats->heap_sector_size - ns_monitor_ptr->heap_high_watermark > high_max) { + ns_monitor_ptr->heap_high_watermark = ns_monitor_ptr->mem_stats->heap_sector_size - high_max; + } + ns_monitor_ptr->heap_critical_watermark = SET_WATERMARK( ns_monitor_ptr->mem_stats->heap_sector_size, - percentage_critical + critical_percentage ); - tr_debug("Monitor set high:%lu, critical:%lu total:%lu", (unsigned long)ns_monitor_ptr->heap_high_watermark, (unsigned long)ns_monitor_ptr->heap_critical_watermark, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size); + if (ns_monitor_ptr->mem_stats->heap_sector_size - ns_monitor_ptr->heap_critical_watermark < critical_min) { + ns_monitor_ptr->heap_critical_watermark = ns_monitor_ptr->mem_stats->heap_sector_size - critical_min; + } + + if (critical_max && ns_monitor_ptr->mem_stats->heap_sector_size - ns_monitor_ptr->heap_critical_watermark > critical_max) { + ns_monitor_ptr->heap_critical_watermark = ns_monitor_ptr->mem_stats->heap_sector_size - critical_max; + } + + tr_info("Monitor set high:%lu, critical:%lu total:%lu", (unsigned long)ns_monitor_ptr->heap_high_watermark, (unsigned long)ns_monitor_ptr->heap_critical_watermark, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size); return 0; } return -1; } -int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) +int ns_monitor_packet_ingress_rate_limit_by_memory(uint32_t minimum_required, uint32_t Maximum_allowed, uint8_t free_heap_percentage) { - if (free_heap_percentage < 100) { - ns_dyn_mem_rate_limiting_threshold_percentage = free_heap_percentage; + /* To make this function dynamic and useful in larger range of memories the minimum value can be given + * + * example limit(1024, 1) + * 32k RAM Limit = 1024 + * 64k RAM Limit = 1024 + * 128k RAM Limit = 1280 + * 320k RAM Limit = 3200 + */ + if (free_heap_percentage == 0 && minimum_required == 0) { + // Disable rate limiting + ns_dyn_mem_rate_limiting_threshold = 0; return 0; } + if (free_heap_percentage > 100) { + // Sanity check this should not be high at all, but dont want to limit without any good reason + return -1; + } - return -1; + const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); + if (ns_dyn_mem_stat && free_heap_percentage) { + ns_dyn_mem_rate_limiting_threshold = ns_dyn_mem_stat->heap_sector_size / 100 * free_heap_percentage; + } + + if (ns_dyn_mem_rate_limiting_threshold < minimum_required) { + ns_dyn_mem_rate_limiting_threshold = minimum_required; + } + + if (Maximum_allowed && ns_dyn_mem_rate_limiting_threshold > Maximum_allowed) { + ns_dyn_mem_rate_limiting_threshold = Maximum_allowed; + } + tr_info("Monitor rate limit incoming packets at:%lu", (unsigned long)ns_dyn_mem_rate_limiting_threshold); + + return 0; } bool ns_monitor_packet_allocation_allowed(void) @@ -212,8 +255,8 @@ bool ns_monitor_packet_allocation_allowed(void) const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); - if (ns_dyn_mem_stat && ns_dyn_mem_rate_limiting_threshold_percentage) { - if (ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_stat->heap_sector_size / 100 * (100 - ns_dyn_mem_rate_limiting_threshold_percentage)) { + if (ns_dyn_mem_stat && ns_dyn_mem_rate_limiting_threshold) { + if (ns_dyn_mem_stat->heap_sector_size - ns_dyn_mem_stat->heap_sector_allocated_bytes < ns_dyn_mem_rate_limiting_threshold) { // Packet allocation not allowed as memory is running low. return false; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_socket.c b/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_socket.c index bd919a99af8..60b5c96b755 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_socket.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Core/ns_socket.c @@ -45,6 +45,8 @@ #define RANDOM_PORT_NUMBER_COUNT (RANDOM_PORT_NUMBER_END - RANDOM_PORT_NUMBER_START + 1) #define RANDOM_PORT_NUMBER_MAX_STEP 500 +static bool socket_reference_limit(socket_t *socket_ptr); + static uint16_t port_counter; static socket_t *socket_instance[SOCKETS_MAX]; @@ -113,6 +115,7 @@ socket_t *socket_pointer_get(int8_t socket) static void socket_data_event_push(buffer_t *buf) { + buf->socket = socket_reference(buf->socket); arm_event_s event = { .receiver = socket_event_handler, .sender = 0, @@ -137,6 +140,7 @@ bool socket_data_queued_event_push(socket_t *socket) }; if (eventOS_event_send(&event) != 0) { + socket_dereference(socket); return false; } return true; @@ -167,12 +171,8 @@ static void socket_cb_event_run(const socket_cb_event_t *event) } } -void socket_buffer_cb_run(socket_t *socket, buffer_t *buffer) +static void socket_buffer_cb_run(socket_t *socket, buffer_t *buffer) { - if (socket->id == -1 || !socket->u.live.fptr) { - buffer_free(buffer); - return; - } eventOS_scheduler_set_active_tasklet(socket->tasklet); @@ -222,9 +222,19 @@ void socket_tasklet_event_handler(arm_event_s *event) } case ARM_SOCKET_DATA_CB: { buffer_t *buf = event->data_ptr; - /* Reference the socket here*/ - socket_t *socket = socket_reference(buf->socket); - if (socket->flags & SOCKET_BUFFER_CB) { + + if (!buf || !buf->socket) { + tr_error("Socket CB: Buf or Socket pointer NULL"); + buffer_free(buf); + break; + } + + socket_t *socket = buf->socket; + + if (socket->id == -1 || !socket->u.live.fptr) { + //Socket is released Free just Buffer + buffer_free(buf); + } else if (socket->flags & SOCKET_BUFFER_CB) { // They just take ownership of the buffer. No read calls. socket_buffer_cb_run(socket, buf); } else { @@ -243,7 +253,9 @@ void socket_tasklet_event_handler(arm_event_s *event) } case ARM_SOCKET_DATA_QUEUED_CB: { socket_t *socket = event->data_ptr; - socket_cb_run(socket); + if (socket) { + socket_cb_run(socket); + } socket_dereference(socket); break; } @@ -454,6 +466,14 @@ socket_t *socket_allocate(socket_type_t type) return socket; } +static bool socket_reference_limit(socket_t *socket_ptr) +{ + if (socket_ptr && socket_ptr->refcount < SOCKET_DEFAULT_REFERENCE_LIMIT) { + return false; + } + return true; +} + /* Increase reference counter on socket, returning now-owned pointer */ socket_t *socket_reference(socket_t *socket_ptr) { @@ -479,7 +499,7 @@ socket_t *socket_dereference(socket_t *socket_ptr) } if (socket_ptr->refcount == 0) { - tr_error("ref underflow"); + tr_error("Socket %d ref underflow", socket_ptr->id); return NULL; } if (--socket_ptr->refcount == 0) { @@ -870,6 +890,13 @@ socket_error_t socket_up(buffer_t *buf) goto drop; } + //Limit here + if (socket_reference_limit(socket)) { + tr_error("Socket reference limit drop RX %u", socket->refcount); + goto drop; + } + + if (socket->rcvq.data_byte_limit == 0) { // Old-style one event per buffer socket_data_event_push(buf); @@ -1092,7 +1119,7 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr #ifndef NO_TCP if (socket_ptr->type == SOCKET_TYPE_STREAM) { - tcp_session_t *tcp_info = tcp_info(inet_pcb); + tcp_session_t *tcp_info = inet_pcb->session; if (!tcp_info) { tr_warn("No TCP session for cur Socket"); ret_val = -3; @@ -1113,6 +1140,12 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr // Everything below this point is non-TCP #endif //NO_TCP + if (socket_reference_limit(socket_ptr)) { + tr_error("Socket reference limit drop TX %u", socket_ptr->refcount); + ret_val = -1; + goto fail; + } + /** * Mark Socket id to buffer meta data */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c index 8784c634d25..7443f30507a 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -93,7 +93,7 @@ int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_r //Validate Client DUID dhcp_link_options_params_t clientDUID; if (libdhcpv6_get_link_address_from_duid(replyPacket->clientDUID.duid, replyPacket->clientDUID.duid_length, replyPacket->clientDUID.type, &clientDUID) == 0) { - dhcp_allocated_address = libdhcpv6_address_allocated_list_scan(serverBase, clientDUID.link_id, clientDUID.link_type, dhcp_ia_non_temporal_params->iaId, dhcp_ia_non_temporal_params->T0, dhcp_ia_non_temporal_params->T1, allocateNew); + dhcp_allocated_address = libdhcpv6_address_allocate(serverBase, clientDUID.link_id, clientDUID.link_type, dhcp_ia_non_temporal_params->iaId, dhcp_ia_non_temporal_params->T0, dhcp_ia_non_temporal_params->T1, allocateNew); } if (dhcp_allocated_address) { address_allocated = true; @@ -109,7 +109,7 @@ int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_r if (!serverBase->addCb(serverBase->interfaceId, &update_info, serverBase->guaPrefix)) { address_allocated = false; - libdhcpv6_address_rm_from_allocated_list(serverBase, dhcp_allocated_address->nonTemporalAddress); + libdhcpv6_address_delete(serverBase, dhcp_allocated_address->nonTemporalAddress); } } } @@ -299,9 +299,9 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { //Delete Server data base if (serverInfo->removeCb) { - uint8_t allocated_address[16]; - libdhcpv6_allocated_address_write(allocated_address, cur, serverInfo); - serverInfo->removeCb(interface, allocated_address, NULL); + uint8_t ipAddress[16]; + libdhcpv6_allocated_address_write(ipAddress, cur, serverInfo); + serverInfo->removeCb(interface, ipAddress, NULL); } } @@ -327,12 +327,19 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], /* Control GUA address for client by DUI.Default value is true * + * Anonymous and disable address list can optimize either + * Using 16 bit suffix to optimize data amount in network + * and having list of assigned addresses meaning larger RAM usage at border router + * + * or Using SLAAC type address generation and not have a list of addresses at Border router + * -> Less RAM usage, but more bandwidth used * * /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 mode true assign addresses anonymously. false define address by Prefix + client id + * /param disable_address_list Dont keep track of assigned Addresses (Can't be used if anonymous) */ -int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list) +int DHCPv6_server_service_set_address_generation_anonymous(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool disable_address_list) { dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); if (!serverInfo) { @@ -340,12 +347,13 @@ int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t gu } - serverInfo->enableAddressAutonous = mode; + serverInfo->anonymousAddress = mode; if (mode) { - serverInfo->disableAddressListAllocation = autonomous_skip_list; + serverInfo->disableAddressList = disable_address_list; } else { - serverInfo->disableAddressListAllocation = false; + serverInfo->disableAddressList = false; } + tr_info("DHCPv6 %s, address list %s", mode ? "anonymous address" : "address mode SLAAC", disable_address_list ? "Not Stored" : "Stored"); return 0; } @@ -375,6 +383,7 @@ int DHCPv6_server_service_duid_update(int8_t interface, uint8_t guaPrefix[static if (!serverInfo) { return -1; } + tr_info("DHCPv6 duid %s", trace_array(duid_ptr, duid_length)); return libdhcpv6_server_duid_set(serverInfo, duid_ptr, duid_type, duid_length); } @@ -399,6 +408,7 @@ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_ } serverInfo->maxSupportedClients = maxClientCount; + tr_info("DHCPv6 maximum clients %"PRIu32, serverInfo->maxSupportedClients); return 0; } @@ -421,6 +431,7 @@ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t gu return -1; } serverInfo->validLifetime = validLifeTimne; + tr_info("DHCPv6 Valid lifetime %"PRIu32, serverInfo->validLifetime); return 0; } @@ -510,7 +521,7 @@ 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, bool autonomous_skip_list) +int DHCPv6_server_service_set_address_generation_anonymous(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list) { (void) interface; (void) guaPrefix; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h index 024a46acdec..5a9fb86949c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h @@ -62,13 +62,19 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds); /* Control GUA address for client by DUI.Default value is true * + * Anonymous and disable address list can optimize either + * Using 16 bit suffix to optimize data amount in network + * and having list of assigned addresses meaning larger RAM usage at border router + * + * or Using SLAAC type address generation and not have a list of addresses at Border router + * -> Less RAM usage, but more bandwidth used * * /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 + * /param mode true assign addresses anonymously. false define address by Prefix + client id + * /param disable_address_list Dont keep track of assigned Addresses (Can't be used if anonymous) */ -int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list); +int DHCPv6_server_service_set_address_generation_anonymous(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/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h index 57025e76efd..b7429c61258 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h @@ -139,6 +139,8 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uin void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]); +void dhcp_relay_agent_interface_id_option_enable(int8_t interface, bool enable); + int dhcp_client_server_address_update(int8_t interface, uint8_t *prefix, uint8_t server_address[static 16]); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c index 559b6ccf1d2..758ce3977ba 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c @@ -175,6 +175,16 @@ void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[sta dhcp_service_relay_instance_enable(dhcp_client->relay_instance, border_router_address); } +void dhcp_relay_agent_interface_id_option_enable(int8_t interface, bool enable) +{ + dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface); + if (!dhcp_client) { + return; + } + + dhcp_service_relay_interface_id_option_enable(dhcp_client->relay_instance, enable); +} + void dhcp_client_delete(int8_t interface) { protocol_interface_info_entry_t *cur = NULL; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_data_buffer.h b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_data_buffer.h index e01ee3a0400..ec694540da0 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_data_buffer.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_data_buffer.h @@ -91,6 +91,13 @@ typedef struct mac_pre_build_frame { uint8_t csma_periods_left; uint8_t fhss_retry_count; uint8_t fhss_cca_retry_count; + uint8_t stored_retry_cnt; + uint8_t stored_cca_cnt; + uint8_t cca_request_restart_cnt; + uint8_t tx_request_restart_cnt; + uint8_t priority; + uint32_t blacklist_start_time_us; + uint16_t blacklist_period_ms; uint16_t initial_tx_channel; uint32_t tx_time; bool upper_layer_request: 1; @@ -101,7 +108,7 @@ typedef struct mac_pre_build_frame { bool ExtendedFrameExchange: 1; bool WaitResponse: 1; unsigned security_mic_len: 5; //Max possible lengths 0, 4, 8, 16 bytes - unsigned priority: 2; + unsigned stored_priority: 2; struct mac_pre_build_frame *next; //Pointer for queue purpose } mac_pre_build_frame_t; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h index 51ce748424f..c13c708e088 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h @@ -42,7 +42,8 @@ typedef enum mac_event_t { MAC_TX_TIMEOUT, MAC_ACK_SECURITY_FAIL, MAC_UNKNOWN_DESTINATION, - MAC_TX_PRECOND_FAIL + MAC_TX_PRECOND_FAIL, + MAC_RETURN_TO_QUEUE } mac_event_t; typedef enum mac_tx_status_type_t { @@ -123,6 +124,7 @@ typedef struct dev_driver_tx_buffer { #define MAC_CCA_MAX 8 #define MAC_DEF_MIN_BE 3 #define MAC_DEF_MAX_BE 5 +#define MAC_PRIORITY_EF_BACKOFF_MULTIPLIER 2 typedef struct mac_active_scan { uint8_t pan_id[2]; @@ -245,6 +247,10 @@ typedef struct protocol_interface_rf_mac_setup { uint8_t mac_sequence; uint8_t mac_tx_retry; uint8_t mac_cca_retry; + uint8_t cca_failure_restart_max; + uint8_t tx_failure_restart_max; + uint16_t blacklist_min_ms; + uint16_t blacklist_max_ms; uint16_t mac_ack_wait_duration; uint8_t mac_mlme_retry_max; uint8_t aUnitBackoffPeriod; @@ -272,7 +278,7 @@ typedef struct protocol_interface_rf_mac_setup { int8_t bc_timer_id; uint32_t mlme_tick_count; uint32_t symbol_rate; - uint32_t symbol_time_us; + uint32_t symbol_time_ns; uint32_t datarate; uint8_t max_ED; uint16_t mlme_ED_counter; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 899813b7249..9d65c24e6fa 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -35,6 +35,7 @@ #include "platform/arm_hal_interrupt.h" #include "common_functions.h" #include "Core/include/ns_monitor.h" +#include "randLIB.h" #include "MAC/IEEE802_15_4/sw_mac_internal.h" #include "MAC/IEEE802_15_4/mac_defines.h" @@ -153,7 +154,7 @@ void mcps_sap_data_req_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, { mcps_data_req_ie_list_t ie_list; memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t)); - mcps_sap_data_req_handler_ext(rf_mac_setup, data_req, &ie_list, NULL); + mcps_sap_data_req_handler_ext(rf_mac_setup, data_req, &ie_list, NULL, MAC_DATA_NORMAL_PRIORITY); } static bool mac_ie_vector_length_validate(ns_ie_iovec_t *ie_vector, uint16_t iov_length, uint16_t *length_out) @@ -192,7 +193,7 @@ static bool mac_ie_vector_length_validate(ns_ie_iovec_t *ie_vector, uint16_t iov } -void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_data_req_t *data_req, const mcps_data_req_ie_list_t *ie_list, const channel_list_s *asynch_channel_list) +void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_data_req_t *data_req, const mcps_data_req_ie_list_t *ie_list, const channel_list_s *asynch_channel_list, mac_data_priority_t priority) { uint8_t status = MLME_SUCCESS; mac_pre_build_frame_t *buffer = NULL; @@ -264,6 +265,27 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set buffer->asynch_request = true; } + //Set Priority level + switch (priority) { + case MAC_DATA_EXPEDITE_FORWARD: + buffer->priority = MAC_PD_DATA_EF_PRIORITY; + // Enable FHSS expedited forwarding + if (rf_mac_setup->fhss_api) { + rf_mac_setup->fhss_api->synch_state_set(rf_mac_setup->fhss_api, FHSS_EXPEDITED_FORWARDING, 0); + } + break; + case MAC_DATA_HIGH_PRIORITY: + buffer->priority = MAC_PD_DATA_HIGH_PRIOTITY; + break; + case MAC_DATA_MEDIUM_PRIORITY: + buffer->priority = MAC_PD_DATA_MEDIUM_PRIORITY; + break; + default: + buffer->priority = MAC_PD_DATA_NORMAL_PRIORITY; + break; + } + + buffer->upper_layer_request = true; buffer->fcf_dsn.frametype = FC_DATA_FRAME; buffer->ExtendedFrameExchange = data_req->ExtendedFrameExchange; @@ -353,6 +375,12 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn); buffer->mac_payload = data_req->msdu; buffer->mac_payload_length = data_req->msduLength; + buffer->cca_request_restart_cnt = rf_mac_setup->cca_failure_restart_max; + // Multiply number of backoffs for higher priority packets + if (buffer->priority == MAC_PD_DATA_EF_PRIORITY) { + buffer->cca_request_restart_cnt *= MAC_PRIORITY_EF_BACKOFF_MULTIPLIER; + } + buffer->tx_request_restart_cnt = rf_mac_setup->tx_failure_restart_max; //check that header + payload length is not bigger than MAC MTU if (data_req->InDirectTx) { @@ -1498,6 +1526,66 @@ static bool mcps_buffer_edfe_data_failure(protocol_interface_rf_mac_setup_s *rf_ return false; } +static void mcps_set_packet_blacklist(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, uint8_t number_of_restarts) +{ + /* + * Random min = configured blacklist min << attempt count, but never larger than configured blacklist max / 2. + * Random max = random min * 2, but never larger than blacklist max. + * Example: + * blacklist_min_ms: 20ms + * blacklist_max_ms: 300ms + * blacklist_retry_attempts: 4 + * + * Packet is blacklisted: + * 20ms - 40ms after 1st failure + * 40ms - 80ms after 2nd failure + * 80ms - 160ms after 3rd failure + * 150ms - 300ms after 4th failure + */ + uint8_t i = 0; + uint32_t blacklist_min_ms = 0; + while (i < number_of_restarts) { + blacklist_min_ms = rf_ptr->blacklist_min_ms << i; + if (blacklist_min_ms > (rf_ptr->blacklist_max_ms / 2)) { + break; + } + i++; + } + uint32_t blacklist_max_ms = blacklist_min_ms * 2; + if (blacklist_min_ms > (rf_ptr->blacklist_max_ms / 2)) { + blacklist_min_ms = (rf_ptr->blacklist_max_ms / 2); + } + if (blacklist_max_ms > rf_ptr->blacklist_max_ms) { + blacklist_max_ms = rf_ptr->blacklist_max_ms; + } + buffer->blacklist_period_ms = randLIB_get_random_in_range(blacklist_min_ms, blacklist_max_ms); + if (!buffer->blacklist_period_ms) { + buffer->blacklist_period_ms++; + } + buffer->blacklist_start_time_us = mac_mcps_sap_get_phy_timestamp(rf_ptr); +} + +static bool mcps_update_packet_request_restart(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) +{ + // Function returns true when buffer needs to be requeued + if (!rf_ptr || !buffer) { + return false; + } + if (rf_ptr->mac_tx_result == MAC_CCA_FAIL && buffer->cca_request_restart_cnt) { + buffer->cca_request_restart_cnt--; + if (buffer->priority == MAC_PD_DATA_EF_PRIORITY) { + mcps_set_packet_blacklist(rf_ptr, buffer, (rf_ptr->cca_failure_restart_max * MAC_PRIORITY_EF_BACKOFF_MULTIPLIER) - buffer->cca_request_restart_cnt); + } else { + mcps_set_packet_blacklist(rf_ptr, buffer, rf_ptr->cca_failure_restart_max - buffer->cca_request_restart_cnt); + } + return true; + } else if (rf_ptr->mac_tx_result == MAC_TX_FAIL && buffer->tx_request_restart_cnt) { + buffer->tx_request_restart_cnt--; + mcps_set_packet_blacklist(rf_ptr, buffer, rf_ptr->tx_failure_restart_max - buffer->tx_request_restart_cnt); + return true; + } + return false; +} static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mac_pre_parsed_frame_t *ack_buf) { @@ -1506,12 +1594,17 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, sw_mac_stats_update(rf_ptr, STAT_MAC_TX_RETRY, rf_ptr->mac_tx_status.retry); mcps_data_conf_t confirm; 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 (!mcps_buffer_edfe_data_failure(rf_ptr, buffer) && ((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), rf_ptr->mac_tx_start_channel) == true) { - + if (!mcps_buffer_edfe_data_failure(rf_ptr, buffer) && ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL) || (rf_ptr->mac_tx_result == MAC_RETURN_TO_QUEUE))) { + // Packet has return to queue status or it needs to be blacklisted and queued + if ((rf_ptr->mac_tx_result == MAC_RETURN_TO_QUEUE) || mcps_update_packet_request_restart(rf_ptr, buffer) == true) { if (rf_ptr->mac_tx_result == MAC_TX_FAIL) { buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry; + } else if (rf_ptr->mac_tx_result == MAC_RETURN_TO_QUEUE) { + buffer->stored_retry_cnt = rf_ptr->mac_tx_retry; + buffer->stored_cca_cnt = rf_ptr->mac_cca_retry; + buffer->stored_priority = buffer->priority; + // Use priority to transmit it first when proper channel is available + buffer->priority = MAC_PD_DATA_TX_IMMEDIATELY; } else { buffer->fhss_retry_count += rf_ptr->mac_tx_status.retry; } @@ -2135,8 +2228,16 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma rf_ptr->macTxRequestAck = false; memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t)); - rf_ptr->mac_cca_retry = 0; - rf_ptr->mac_tx_retry = 0; + if (buffer->priority == MAC_PD_DATA_TX_IMMEDIATELY) { + // Return original priority and retry/CCA counts + buffer->priority = buffer->stored_priority; + rf_ptr->mac_tx_retry = rf_ptr->mac_tx_status.retry = buffer->stored_retry_cnt; + rf_ptr->mac_cca_retry = rf_ptr->mac_tx_status.cca_cnt = buffer->stored_cca_cnt; + buffer->stored_retry_cnt = buffer->stored_cca_cnt = 0; + } else { + rf_ptr->mac_tx_retry = 0; + rf_ptr->mac_cca_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) { @@ -2198,6 +2299,17 @@ int mac_convert_frame_type_to_fhss(uint8_t frame_type) return FHSS_DATA_FRAME; } +static bool mcps_check_packet_blacklist(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) +{ + if (!buffer->blacklist_period_ms) { + return false; + } + if ((mac_mcps_sap_get_phy_timestamp(rf_mac_setup) - buffer->blacklist_start_time_us) >= (buffer->blacklist_period_ms * 1000)) { + return false; + } + return true; +} + void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) { if (!rf_mac_setup || !buffer) { @@ -2216,9 +2328,9 @@ void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup } if (rf_mac_setup->fhss_api && (buffer->asynch_request == false)) { uint16_t frame_length = buffer->mac_payload_length + buffer->headerIeLength + buffer->payloadsIeLength; - if (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), - buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), frame_length, - rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == false) { + if ((mcps_check_packet_blacklist(rf_mac_setup, buffer) == true) || rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), + buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), frame_length, + rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == false) { if (buffer->ExtendedFrameExchange) { rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; } @@ -2321,9 +2433,12 @@ static mac_pre_build_frame_t *mcps_sap_pd_req_queue_read(protocol_interface_rf_m // With FHSS, check TX conditions if (rf_mac_setup->fhss_api) { while (buffer) { - if (buffer->asynch_request || (flush == true) || (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), - buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), buffer->mac_payload_length, - rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == true)) { + if (buffer->asynch_request || + (flush == true) || + ((mcps_check_packet_blacklist(rf_mac_setup, buffer) == false) && + (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), + buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), buffer->mac_payload_length, + rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == true))) { break; } prev = buffer; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.h index 3992ae31251..d79343546ef 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -49,6 +49,8 @@ typedef enum { #define MAC_PD_DATA_NORMAL_PRIORITY 0 //Normal MCPS DATA REQ #define MAC_PD_DATA_MEDIUM_PRIORITY 1 //Indirect Data which is polled #define MAC_PD_DATA_HIGH_PRIOTITY 2 //Beacon request Beacon response +#define MAC_PD_DATA_EF_PRIORITY 3 //Expedited forwarding +#define MAC_PD_DATA_TX_IMMEDIATELY 4 //Only for packets whose transmission was interrupted by wrong channel type. E.g. unicast on broadcast channel. #define MCPS_SAP_DATA_IND_EVENT 1 #define MCPS_SAP_DATA_CNF_EVENT 2 @@ -121,7 +123,7 @@ int8_t mac_virtual_sap_data_cb(void *identifier, struct arm_phy_sap_msg_s *messa void mcps_sap_data_req_handler(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_data_req_s *data_req); -void mcps_sap_data_req_handler_ext(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_data_req_s *data_req, const struct mcps_data_req_ie_list *ie_list, const channel_list_s *asynch_channel_list); +void mcps_sap_data_req_handler_ext(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_data_req_s *data_req, const struct mcps_data_req_ie_list *ie_list, const channel_list_s *asynch_channel_list, mac_data_priority_t priority); void mac_mcps_trig_buffer_from_queue(struct protocol_interface_rf_mac_setup *rf_mac_setup); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c index 0e6ae5ca36a..c6c0d01cc43 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c @@ -449,6 +449,8 @@ int8_t mac_mlme_reset(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlm rf_mac_setup->macWaitingData = false; rf_mac_setup->macDataPollReq = false; rf_mac_setup->macRxDataAtPoll = false; + rf_mac_setup->macTxProcessActive = false; + rf_mac_setup->mac_ack_tx_active = false; //Clean MAC if (reset->SetDefaultPIB) { tr_debug("RESET MAC PIB"); @@ -596,7 +598,7 @@ static int8_t mac_mlme_8bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, break; case macMaxBE: - if (value > 8 || value < 3) { + if (value > 8 || value < 1) { return -1; } rf_mac_setup->macMaxBE = value; @@ -652,11 +654,11 @@ void mac_extended_mac_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const static uint32_t mac_calc_ack_wait_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t symbols) { - uint32_t AckWaitDuration = 0; + uint32_t AckWaitDuration_us = 0; if (rf_mac_setup->rf_csma_extension_supported) { - AckWaitDuration = symbols * rf_mac_setup->symbol_time_us; + AckWaitDuration_us = (symbols * rf_mac_setup->symbol_time_ns) / 1000; } - return AckWaitDuration; + return AckWaitDuration_us; } static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) @@ -747,6 +749,18 @@ static int8_t mac_mlme_set_multi_csma_parameters(protocol_interface_rf_mac_setup return 0; } +static int8_t mac_mlme_set_data_request_restart_config(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) +{ + mlme_request_restart_config_t request_restart_config; + memcpy(&request_restart_config, set_req->value_pointer, sizeof(mlme_request_restart_config_t)); + rf_mac_setup->cca_failure_restart_max = request_restart_config.cca_failure_restart_max; + rf_mac_setup->tx_failure_restart_max = request_restart_config.tx_failure_restart_max; + rf_mac_setup->blacklist_min_ms = request_restart_config.blacklist_min_ms; + rf_mac_setup->blacklist_max_ms = request_restart_config.blacklist_max_ms; + tr_debug("Request restart config: CCA %u, TX %u, min %u, max %u", rf_mac_setup->cca_failure_restart_max, rf_mac_setup->tx_failure_restart_max, rf_mac_setup->blacklist_min_ms, rf_mac_setup->blacklist_max_ms); + return 0; +} + int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) { if (!set_req || !rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) { @@ -816,6 +830,8 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m return 0; case macMultiCSMAParameters: return mac_mlme_set_multi_csma_parameters(rf_mac_setup, set_req); + case macRequestRestart: + return mac_mlme_set_data_request_restart_config(rf_mac_setup, set_req); case macRfConfiguration: 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); @@ -1107,8 +1123,8 @@ static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_se { if (rf_mac_setup->rf_csma_extension_supported) { rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_SYMBOLS_PER_SECOND, (uint8_t *) &rf_mac_setup->symbol_rate); - rf_mac_setup->symbol_time_us = 1000000 / rf_mac_setup->symbol_rate; - tr_debug("SW-MAC driver support rf extension %"PRIu32" symbol/seconds %"PRIu32" us symbol time length", rf_mac_setup->symbol_rate, rf_mac_setup->symbol_time_us); + rf_mac_setup->symbol_time_ns = 1000000000 / rf_mac_setup->symbol_rate; + tr_debug("SW-MAC driver support rf extension %"PRIu32" symbol/seconds %"PRIu32" ns symbol time length", rf_mac_setup->symbol_rate, rf_mac_setup->symbol_time_ns); return 0; } return -1; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c index 6a6b4a3f93c..2a61f10ee9d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -97,7 +97,7 @@ uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup) uint32_t backoff_in_us; //Multiple aUnitBackoffPeriod symbol time if (rf_mac_setup->rf_csma_extension_supported) { - backoff_in_us = backoff * rf_mac_setup->aUnitBackoffPeriod * rf_mac_setup->symbol_time_us; + backoff_in_us = backoff * rf_mac_setup->aUnitBackoffPeriod * (rf_mac_setup->symbol_time_ns / 1000); } else { backoff_in_us = backoff * rf_mac_setup->backoff_period_in_10us * 10; } @@ -189,6 +189,9 @@ int8_t mac_plme_cca_req(protocol_interface_rf_mac_setup_s *rf_mac_setup) length = tx_buf->len; } if (dev_driver->tx(buffer, length, 1, PHY_LAYER_PAYLOAD) == 0) { +#ifdef TIMING_TOOL_TRACES + tr_info("%u CSMA_start", mac_mcps_sap_get_phy_timestamp(rf_mac_setup)); +#endif return 0; } @@ -451,9 +454,13 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return -1; } - if (status == PHY_LINK_CCA_PREPARE) { - +#ifdef TIMING_TOOL_TRACES + if ((status == PHY_LINK_CCA_FAIL) || (status == PHY_LINK_CCA_FAIL_RX) || (status == PHY_LINK_CCA_PREPARE)) { + tr_info("%u CSMA_done", mac_mcps_sap_get_phy_timestamp(rf_ptr)); + } +#endif + if (status == PHY_LINK_CCA_PREPARE) { if (rf_ptr->mac_ack_tx_active || rf_ptr->mac_edfe_tx_active) { goto VALIDATE_TX_TIME; } @@ -485,10 +492,12 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r mac_sap_cca_fail_cb(rf_ptr, 0xffff); return PHY_TX_NOT_ALLOWED; } - // When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back - // to queue by using CCA fail event + // When FHSS TX handle returns -3, we are trying to: + // - transmit broadcast packet on unicast channel + // - transmit unicast packet on broadcast channel + // Push back to queue to allow sending applicable packet if (tx_handle_retval == -3) { - mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); + mac_tx_done_state_set(rf_ptr, MAC_RETURN_TO_QUEUE); return PHY_TX_NOT_ALLOWED; } else if (tx_handle_retval == -2) { mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION); @@ -505,6 +514,9 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r active_buf->csma_periods_left--; active_buf->tx_time += rf_ptr->multi_cca_interval; mac_pd_sap_set_phy_tx_time(rf_ptr, active_buf->tx_time, true); +#ifdef TIMING_TOOL_TRACES + tr_info("%u CSMA_start", mac_mcps_sap_get_phy_timestamp(rf_ptr)); +#endif return PHY_RESTART_CSMA; } } @@ -547,7 +559,8 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r // Do not update CCA count when Ack is received, it was already updated with PHY_LINK_TX_SUCCESS event // Do not update CCA count when CCA_OK is received, PHY_LINK_TX_SUCCESS will update it - if ((status != PHY_LINK_TX_DONE) && (status != PHY_LINK_TX_DONE_PENDING) && (status != PHY_LINK_CCA_OK)) { + // Do not update CCA count when CCA fail was because of active reception, MAC will restart CCA check in this case + if ((status != PHY_LINK_TX_DONE) && (status != PHY_LINK_TX_DONE_PENDING) && (status != PHY_LINK_CCA_OK) && (status != PHY_LINK_CCA_FAIL_RX)) { /* For PHY_LINK_TX_SUCCESS and PHY_LINK_CCA_FAIL cca_retry must always be > 0. * PHY_LINK_TX_FAIL either happened during transmission or when waiting Ack -> we must use the CCA count given by PHY. */ @@ -581,6 +594,9 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r } else if (status == PHY_LINK_CCA_FAIL) { waiting_ack = false; tx_completed = false; + } else if (status == PHY_LINK_CCA_FAIL_RX) { + waiting_ack = false; + tx_completed = false; } else if (status == PHY_LINK_CCA_OK) { waiting_ack = false; tx_completed = false; @@ -608,6 +624,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r break; case PHY_LINK_CCA_FAIL: + case PHY_LINK_CCA_FAIL_RX: mac_sap_cca_fail_cb(rf_ptr, failed_channel); break; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c index 0897b78bb9e..ed06964ab5d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -600,7 +600,7 @@ void mac_sec_mib_key_device_frame_counter_set(mlme_key_descriptor_t *key_descpri if (key_descpription_table->KeyFrameCounterPerKey) { uint32_t *counter_ptr = key_descpription_table->KeyDeviceFrameCounterList + attribute_index; *counter_ptr = frame_counter; - } else { + } else if (device_info) { device_info->FrameCounter = frame_counter; } } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c index 7fd08c6d25a..7e287ee5148 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/sw_mac.c @@ -58,7 +58,7 @@ static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *e static void mlme_req(const mac_api_t *api, mlme_primitive id, const void *data); static void mcps_req(const mac_api_t *api, const mcps_data_req_t *data); -static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list); +static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list, mac_data_priority_t priority); static uint8_t purge_req(const mac_api_t *api, const mcps_purge_t *data); static int8_t macext_mac64_address_set(const mac_api_t *api, const uint8_t *mac64); static int8_t macext_mac64_address_get(const mac_api_t *api, mac_extended_address_type type, uint8_t *mac64_buf); @@ -575,22 +575,22 @@ void mlme_req(const mac_api_t *api, mlme_primitive id, const void *data) } } -void mcps_req(const mac_api_t *api, const mcps_data_req_t *data) +static void mcps_req(const mac_api_t *api, const mcps_data_req_t *data) { //TODO: Populate linked list when present if (mac_store.mac_api == api) { /* Call direct new API but without IE extensions */ mcps_data_req_ie_list_t ie_list; memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t)); - mcps_sap_data_req_handler_ext(mac_store.setup, data, &ie_list, NULL); + mcps_sap_data_req_handler_ext(mac_store.setup, data, &ie_list, NULL, MAC_DATA_NORMAL_PRIORITY); } } -void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list) +static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list, mac_data_priority_t priority) { //TODO: Populate linked list when present if (mac_store.mac_api == api) { - mcps_sap_data_req_handler_ext(mac_store.setup, data, ie_ext, asynch_channel_list); + mcps_sap_data_req_handler_ext(mac_store.setup, data, ie_ext, asynch_channel_list, priority); } } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MPL/mpl.c b/connectivity/nanostack/sal-stack-nanostack/source/MPL/mpl.c index 68c56b95c14..1ab5b21cf1a 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MPL/mpl.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MPL/mpl.c @@ -1065,6 +1065,7 @@ static buffer_t *mpl_exthdr_provider(buffer_t *buf, ipv6_exthdr_stage_t stage, i if (!domain) { // We will need to tunnel - do nothing on the inner packet *result = 0; + buf->options.ipv6_use_min_mtu = 1; return buf; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/Include/protocol.h b/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/Include/protocol.h index a9f26329db1..0ca9c30a655 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/Include/protocol.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/Include/protocol.h @@ -124,6 +124,7 @@ typedef enum icmp_state { ER_BOOTSTRAP_NEW_FRAGMENT_START, ER_WAIT_RESTART, ER_RPL_LOCAL_REPAIR, + ER_RPL_NETWORK_LEAVING, } icmp_state_t; typedef enum { @@ -447,6 +448,8 @@ struct protocol_interface_info_entry { br_info_t *border_router_setup; struct load_balance_api *lb_api; struct red_info_s *random_early_detection; + struct red_info_s *llc_random_early_detection; + struct red_info_s *llc_eapol_random_early_detection; neigh_cache_s neigh_cache; pan_blaclist_cache_s pan_blaclist_cache; pan_coordinator_blaclist_cache_s pan_cordinator_black_list; @@ -471,6 +474,7 @@ struct protocol_interface_info_entry { int8_t (*if_down)(struct protocol_interface_info_entry *cur); int8_t (*if_up)(struct protocol_interface_info_entry *cur); void (*if_stack_buffer_handler)(buffer_t *); + void (*if_common_forwarding_out_cb)(struct protocol_interface_info_entry *, buffer_t *); bool (*if_ns_transmit)(struct protocol_interface_info_entry *cur, ipv6_neighbour_t *neighCacheEntry, bool unicast, uint8_t seq); bool (*if_map_ip_to_link_addr)(struct protocol_interface_info_entry *cur, const uint8_t *ip_addr, addrtype_t *ll_type, const uint8_t **ll_addr_out); bool (*if_map_link_addr_to_ip)(struct protocol_interface_info_entry *cur, addrtype_t ll_type, const uint8_t *ll_addr, uint8_t *ip_addr_out); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c b/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c index 168293a4b78..45f0c413841 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c @@ -265,6 +265,7 @@ void core_timer_event_handle(uint16_t ticksUpdate) cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, false); } etx_cache_timer(cur->id, seconds); + lowpan_adaptation_interface_slow_timer(cur); } } else if (cur->nwk_id == IF_IPV6) { //Slow Pointer Update @@ -461,6 +462,7 @@ static void protocol_core_base_init(protocol_interface_info_entry_t *entry, nwk_ entry->ipv6_configure = NULL; entry->if_lowpan_security_params = NULL; entry->if_ns_transmit = NULL; + entry->if_common_forwarding_out_cb = NULL; entry->if_special_forwarding = NULL; entry->if_snoop = NULL; entry->if_icmp_handler = NULL; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c index b6724d65fd2..522d85107a8 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.c @@ -55,6 +55,7 @@ #include "RPL/rpl_downward.h" #include "RPL/rpl_policy.h" #include "RPL/rpl_control.h" +#include "6LoWPAN/ws/ws_common.h" #define TRACE_GROUP "rplc" @@ -204,6 +205,12 @@ void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size) rpl_policy_set_mrhof_parent_set_size(parent_set_size); } +/* True Force RPL to use IPv6 tunneling when it send and forward data to Border router direction, This feature is disabled by default */ +void rpl_control_set_force_tunnel(bool requested) +{ + rpl_policy_force_tunnel_set(requested); +} + /* 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]) { @@ -300,6 +307,25 @@ bool rpl_control_probe_parent_candidate(protocol_interface_info_entry_t *interfa return false; } +uint16_t rpl_control_neighbor_info_get(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t *global_address) +{ + + if (!interface->rpl_domain) { + return 0xffff; + } + ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); + if (neighbour) { + const uint8_t *global_address_ptr = rpl_neighbour_global_address(neighbour); + if (global_address && global_address_ptr) { + memcpy(global_address, global_address_ptr, 16); + } + return rpl_instance_candidate_rank(neighbour); + } + } + return 0xffff; +} + 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) { @@ -399,6 +425,7 @@ static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_et if (!cur || !cur->rpl_domain) { return; } + (void) attribute_index; // 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); @@ -444,6 +471,9 @@ rpl_domain_t *rpl_control_create_domain(void) ns_list_init(&domain->instances); domain->non_storing_downstream_interface = -1; domain->callback = NULL; + domain->new_parent_add = NULL; + domain->parent_dis = NULL; + domain->prefix_cb = NULL; domain->cb_handle = NULL; domain->force_leaf = false; domain->process_routes = true; @@ -520,12 +550,13 @@ void rpl_control_free_domain_instances_from_interface(protocol_interface_info_en } } -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, rpl_parent_dis_callback_t parent_dis, void *cb_handle) { domain->callback = callback; domain->prefix_cb = prefix_learn_cb; domain->cb_handle = cb_handle; domain->new_parent_add = new_parent_add; + domain->parent_dis = parent_dis; } /* To do - this should live somewhere nicer. Basically a bootstrap @@ -554,6 +585,11 @@ bool rpl_control_have_dodag(rpl_domain_t *domain) typedef void rpl_control_predicate_loop_fn_t(rpl_instance_t *instance, rpl_dodag_version_t *version, void *arg); +typedef struct rpl_loopfn_trigger_unicast_dio_arg { + struct protocol_interface_info_entry *interface; + const uint8_t *dst; +} rpl_loopfn_trigger_unicast_dio_arg_t; + /* Callbacks for rpl_control_predicate_loop */ static void rpl_loopfn_reset_dio_timer(rpl_instance_t *instance, rpl_dodag_version_t *dodag_version, void *handle) @@ -562,12 +598,19 @@ static void rpl_loopfn_reset_dio_timer(rpl_instance_t *instance, rpl_dodag_versi (void)handle; rpl_instance_inconsistency(instance); -} + //Check was Multicast DIS from parent + rpl_loopfn_trigger_unicast_dio_arg_t *arg = handle; + rpl_domain_t *domain = arg->interface->rpl_domain; + if (domain && domain->parent_dis) { + + if (rpl_instance_address_is_parent(instance, arg->dst)) { + // Call Multicast DIS parent Callback + domain->parent_dis(arg->dst, arg->interface, instance); + } + } -typedef struct rpl_loopfn_trigger_unicast_dio_arg { - struct protocol_interface_info_entry *interface; - const uint8_t *dst; -} rpl_loopfn_trigger_unicast_dio_arg_t; + +} static void rpl_loopfn_trigger_unicast_dio(rpl_instance_t *instance, rpl_dodag_version_t *dodag_version, void *handle) { @@ -879,6 +922,11 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t * uint32_t preferred = common_read_32_bit(ptr + 8); const uint8_t *prefix = ptr + 16; + if (ws_info(cur)) { + //For Wi-SUN Interoperability force length to 64 + prefix_len = 64; + } + if (rpl_upward_accept_prefix_update(dodag, neighbour, pref_parent)) { /* Store prefixes for possible forwarding */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h index 5b9f6c26cf9..e13f552a09b 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_control.h @@ -36,6 +36,7 @@ typedef enum rpl_event { RPL_EVENT_LOCAL_REPAIR_START, /* RPL start scanning new parent by multicast DIS user can disable beacon request responser here*/ RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS, /* RPL not sending DIS anymore user can report bootstrap error */ RPL_EVENT_DAO_PARENT_ADD, /* RPL indicate that DAO downward Parent has been added */ + RPL_EVENT_POISON_FINISHED, /* RPL have finished Dodag Poison proces */ } rpl_event_t; typedef void rpl_domain_callback_t(rpl_event_t event, void *handle); @@ -44,6 +45,8 @@ typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, 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 void rpl_parent_dis_callback_t(const uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance); + typedef struct rpl_route_info { uint8_t node[8]; /* IID of parent in parent child relation table */ uint8_t parent[8]; /* IID of child in parent child relation table */ @@ -64,6 +67,7 @@ typedef struct rpl_domain { rpl_domain_callback_t *callback; rpl_prefix_callback_t *prefix_cb; rpl_new_parent_callback_t *new_parent_add; + rpl_parent_dis_callback_t *parent_dis; void *cb_handle; } rpl_domain_t; @@ -158,7 +162,7 @@ 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, rpl_parent_dis_callback_t parent_dis, void *cb_handle); /* Target publishing */ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime); @@ -166,6 +170,7 @@ void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]) bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); bool rpl_control_is_dodag_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint16_t candidate_cmp_limiter); bool rpl_control_probe_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); +uint16_t rpl_control_neighbor_info_get(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t *global_address); 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); @@ -176,6 +181,7 @@ bool rpl_control_find_worst_neighbor(struct protocol_interface_info_entry *inter /* Parent link confirmation API extension */ void rpl_control_request_parent_link_confirmation(bool requested); +void rpl_control_set_force_tunnel(bool requested); void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count); void rpl_control_set_address_registration_timeout(uint16_t timeout_in_minutes); void rpl_control_set_dao_retry_count(uint8_t count); @@ -200,6 +206,7 @@ const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_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); +void rpl_control_instant_poison(struct protocol_interface_info_entry *cur, rpl_domain_t *domain); #else /* HAVE_RPL */ @@ -211,6 +218,7 @@ uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain); #define rpl_control_address_register_done(interface, ll_addr, status) (false) #define rpl_policy_mrhof_parent_set_size_get(domain) (0) #define rpl_control_set_mrhof_parent_set_size(parent_set_size) +#define rpl_control_instant_poison(cur, domain) ((void) 0) #endif /* HAVE_RPL */ #endif /* RPL_CONTROL_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_data.c b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_data.c index 236b6a5431e..099192a1079 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_data.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_data.c @@ -46,6 +46,7 @@ #include "RPL/rpl_structures.h" #include "RPL/rpl_policy.h" #include "RPL/rpl_data.h" +#include "6LoWPAN/ws/ws_common.h" #define TRACE_GROUP "RPLa" @@ -334,8 +335,24 @@ static buffer_t *rpl_data_exthdr_provider_hbh_2(buffer_t *buf, rpl_instance_t *i bool destination_in_instance = false; uint16_t ext_size = 0; - if (addr_ipv6_equal(route_info->next_hop_addr, buf->dst_sa.address) || - addr_ipv6_equal(buf->dst_sa.address, dodag->id)) { + + // Limit creation of multi-hop RPL packets + // Previous code created multi-hop RPL packets as much as possible, + // sending direct to border router in particular. + // This has caused WiSUN interop problems, so limit this. + // a) When creating a basic packet, have a policy option that prevents + // direct RPL header insertion, forcing tunnelling. This means + // we never put a RPL header on the innermost packet. Option is + // off by default, except for WiSUN, as it increases packet size + // when talking to the border router (eg DAOs). + // b) When putting a packet into a tunnel, set the tunnel exit to the + // next hop always, rather than having a special case for exiting + // at the border router. This is probably a net benefit to packet + // size because of the LL addresses used on the outer header, so + // this is an unconditional change. Exception remains for local + // DODAGs, where the destination address must be the DODAGID. + if (addr_ipv6_equal(route_info->next_hop_addr, buf->dst_sa.address) || (!rpl_policy_force_tunnel() && + addr_ipv6_equal(buf->dst_sa.address, dodag->id))) { destination_in_instance = true; if (buf->rpl_option) { @@ -357,6 +374,7 @@ static buffer_t *rpl_data_exthdr_provider_hbh_2(buffer_t *buf, rpl_instance_t *i case IPV6_EXTHDR_INSERT: { if (!destination_in_instance) { /* We don't add a header - we'll do it on the tunnel */ + buf->options.ipv6_use_min_mtu = 1; *result = 0; return buf; } @@ -409,10 +427,12 @@ static buffer_t *rpl_data_exthdr_provider_hbh_2(buffer_t *buf, rpl_instance_t *i rpl_data_locate_info(buf, &opt, NULL); if (!opt) { *result = IPV6_EXTHDR_MODIFY_TUNNEL; - // Tunnel to next hop in general case, but if going to DODAGID, - // it can tunnel all the way (and it HAS to if it is a local - // DODAG). - if (!addr_ipv6_equal(buf->dst_sa.address, dodag->id)) { + // Tunnel to next hop always, even if we could tunnel all + // the way to DODAG root (this may be better for + // packet compression, and it was found to be necessary for + // Wi-SUN interoperability). Except for local DODAGs the + // destination must be the DODAGID, so retain that in dst_sa. + if (!rpl_instance_id_is_local(instance->id)) { memcpy(buf->dst_sa.address, route_info->next_hop_addr, 16); } buf->src_sa.addr_type = ADDR_NONE; // force auto-selection @@ -427,18 +447,20 @@ static buffer_t *rpl_data_exthdr_provider_hbh_2(buffer_t *buf, rpl_instance_t *i * strictly less for Down packets and strictly greater for Up. */ sender_rank = common_read_16_bit(opt + 4); - rpl_cmp_t cmp = rpl_rank_compare_dagrank_rank(dodag, sender_rank, instance->current_rank); - rpl_cmp_t expected_cmp = (opt[2] & RPL_OPT_DOWN) ? RPL_CMP_LESS : RPL_CMP_GREATER; - if (cmp != expected_cmp) { - /* Set the Rank-Error bit; if already set, drop */ - if (opt[2] & RPL_OPT_RANK_ERROR) { - protocol_stats_update(STATS_RPL_ROUTELOOP, 1); - tr_info("Forwarding inconsistency R"); - rpl_instance_inconsistency(instance); - *result = -1; - return buf; - } else { - opt[2] |= RPL_OPT_RANK_ERROR; + if (sender_rank != 0) { + rpl_cmp_t cmp = rpl_rank_compare_dagrank_rank(dodag, sender_rank, instance->current_rank); + rpl_cmp_t expected_cmp = (opt[2] & RPL_OPT_DOWN) ? RPL_CMP_LESS : RPL_CMP_GREATER; + if (cmp != expected_cmp) { + /* Set the Rank-Error bit; if already set, drop */ + if (opt[2] & RPL_OPT_RANK_ERROR) { + protocol_stats_update(STATS_RPL_ROUTELOOP, 1); + tr_info("Forwarding inconsistency R"); + rpl_instance_inconsistency(instance); + *result = -1; + return buf; + } else { + opt[2] |= RPL_OPT_RANK_ERROR; + } } } } @@ -944,6 +966,7 @@ static buffer_t *rpl_data_exthdr_provider_srh(buffer_t *buf, ipv6_exthdr_stage_t if (!buf->options.tunnelled) { if (stage == IPV6_EXTHDR_SIZE || stage == IPV6_EXTHDR_INSERT) { *result = 0; + buf->options.ipv6_use_min_mtu = 1; return buf; } } @@ -1034,6 +1057,11 @@ buffer_t *rpl_data_process_routing_header(buffer_t *buf, protocol_interface_info buf->options.ip_extflags |= IPEXT_SRH_RPL; + if (ws_info(cur)) { + //Call SRC route header handler hook to Wi-SUN refresh border router alive + ws_common_border_router_alive_update(cur); + } + uint16_t hlen = (ptr[1] + 1) * 8; uint8_t segs_left = ptr[3]; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c index 5e6b7258d4e..11a67375979 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.c @@ -48,6 +48,17 @@ static uint8_t rpl_policy_mrhof_parent_set_size_conf = 3; // default parent set static uint16_t rpl_policy_minimum_dao_target_refresh_conf = 0; // by default follow the configuration static uint16_t rpl_policy_address_registration_timeout_value = 0; // Address registration timeouts in minutes 0 use address lifetime +static bool rpl_policy_force_tunnel_to_BR = false; + +bool rpl_policy_force_tunnel(void) +{ + return rpl_policy_force_tunnel_to_BR; +} + +void rpl_policy_force_tunnel_set(bool enable) +{ + rpl_policy_force_tunnel_to_BR = enable; +} /* TODO - application API to control when to join new instances / DODAGs * * Eg, allow application to ignore local DODAGs, or specify known instance IDs, diff --git a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h index ac9ca67a1f5..91e49175879 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_policy.h @@ -21,6 +21,9 @@ #include "Core/include/ns_address_internal.h" #include "rpl_control.h" +bool rpl_policy_force_tunnel(void); +void rpl_policy_force_tunnel_set(bool enable); + bool rpl_policy_join_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid); bool rpl_policy_join_dodag(rpl_domain_t *domain, uint8_t g_mop_prf, uint8_t instance_id, const uint8_t *dodagid); bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_t *conf, bool *leaf_only); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c index 2a606da2ea8..496313a08a3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c @@ -347,6 +347,14 @@ void rpl_instance_poison(rpl_instance_t *instance, uint8_t count) rpl_instance_inconsistency(instance); } +void rpl_control_instant_poison(protocol_interface_info_entry_t *cur, rpl_domain_t *domain) +{ + ns_list_foreach(rpl_instance_t, instance, &domain->instances) { + rpl_instance_poison(instance, 1); + rpl_instance_dio_trigger(instance, cur, NULL); + } +} + void rpl_instance_force_leaf(rpl_instance_t *instance) { instance->current_rank = RPL_RANK_INFINITE; @@ -363,7 +371,7 @@ void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t de } } if (instance->parent_selection_timer == 0 || instance->parent_selection_timer > delay) { - instance->parent_selection_timer = randLIB_randomise_base(delay, 0x8000, 0x999A) /* Random between delay * 1.0-1.2 */; + instance->parent_selection_timer = randLIB_randomise_base(delay, 0x8000, 0xc000) /* Random between delay * 1.0-1.5 */; tr_debug("Timed parent triggered %u", instance->parent_selection_timer); } } @@ -1594,6 +1602,45 @@ void rpl_instance_remove_interface(rpl_instance_t *instance, int8_t if_id) } } +static bool rpl_instance_parent_selected(rpl_instance_t *instance) +{ + if (rpl_instance_am_root(instance)) { + return true; + } + + // We don't have DAO target generated + if (ns_list_count(&instance->dao_targets) == 0) { + return false; + } + + // We don't have any valid parent selected + if (!rpl_instance_parent_selection_ready(instance)) { + return false; + } + + return true; +} + +static bool rpl_instance_dao_route_registered(rpl_instance_t *instance) +{ + if (rpl_instance_am_root(instance)) { + //Border router is allways at stable state + return true; + } + + /* Address registrations for parent ongoing*/ + if (rpl_policy_parent_confirmation_requested() && instance->pending_neighbour_confirmation) { + return false; + } + + /* 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 false; + } + + return true; +} + /* Trigger DIO transmission - all interfaces multicast if addr+cur are NULL, else unicast */ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_entry_t *cur, const uint8_t *addr) { @@ -1620,12 +1667,23 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_ instance->poison_count--; rank = RPL_RANK_INFINITE; tr_debug("Poison count -> set RPL_RANK_INFINITE"); + if (instance->poison_count == 0) { + //Report RPL user that Poison message is triggered + rpl_control_event(instance->domain, RPL_EVENT_POISON_FINISHED); + } } // Always send config in unicasts (as required), never in multicasts (optional) rpl_dodag_conf_t *conf; if (addr) { conf = &dodag->config; + //Unicast + if (rank != RPL_RANK_INFINITE) { + if (!rpl_instance_parent_selected(instance)) { + tr_debug("parent selection not ready. DIO rank INFINITE"); + rank = RPL_RANK_INFINITE; + } + } } else if (dodag->new_config_advertisment_count < rpl_policy_dio_multicast_config_advertisment_min_count()) { conf = &dodag->config; if (dodag->new_config_advertisment_count < 0xfe) { @@ -1637,6 +1695,10 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_ rpl_control_transmit_dio(instance->domain, cur, instance->id, dodag_version->number, rank, dodag->g_mop_prf, instance->dtsn, dodag, dodag->id, conf, addr); + if (addr) { + return; + } + dodag_version->last_advertised_rank = rank; /* When we advertise a new lowest rank, need to re-evaluate our rank limits */ @@ -1716,8 +1778,10 @@ void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair) instance->repair_dis_count = 0; } else { instance->repair_dis_timer = 0; - instance->advertised_dodag_membership_since_last_repair = false; + } + //SET False allways for guarantee reboot possibility + instance->advertised_dodag_membership_since_last_repair = false; /* When repair ends, eliminate all higher-rank neighbours (potential sub-DODAG) from table */ if (!repair && instance->current_dodag_version) { @@ -1843,21 +1907,12 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) /* Important to always send DIOs if we ever have sent any, so we can indicate problems to others */ if (!rpl_instance_am_root(instance) && !instance->poison_count && !instance->advertised_dodag_membership_since_last_repair && rpl_policy_parent_confirmation_requested()) { - // We don't have DAO target generated - if (ns_list_count(&instance->dao_targets) == 0) { - return; - } - - // We don't have any valid parent selected - if (!rpl_instance_parent_selection_ready(instance)) { - return; - } - /* Address registrations for parent ongoing*/ - if (instance->pending_neighbour_confirmation) { + //Validate Parent is selected and registered + if (!rpl_instance_parent_selected(instance)) { 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) { + //Verify that DAO is registered + if (!rpl_instance_dao_route_registered(instance)) { return; } } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/Common/security_lib.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/Common/security_lib.c index ff3d31a0beb..a48616a086f 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/Common/security_lib.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/Common/security_lib.c @@ -128,6 +128,10 @@ void tls_server_hash_copy(uint8_t *ptr, tls_msg_t *tmp_msg, sec_suite_t *suite) tls_build_server_hello_msg(ptr, suite->tls_session); tls_handshake_copy(tmp_msg, t_heap); tr_debug("Pana server S-Hello,Cert hash"); +#else + (void) ptr; + (void) tmp_msg; + (void) suite; #endif } #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/PANA/pana_server.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/PANA/pana_server.c index e2b863e8f7e..092b4ad59c9 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/PANA/pana_server.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/PANA/pana_server.c @@ -1721,6 +1721,8 @@ static void pana_client_authentication_fail(sec_suite_t *suite) int8_t pana_server_nvm_callback_set(pana_server_update_cb *update_cb, pana_server_session_get_cb *nvm_get, pana_server_session_get_by_id_cb *nvm_session_get, uint8_t *nvm_static_buffer) { (void)update_cb; + (void)nvm_get; + (void)nvm_session_get; (void)nvm_static_buffer; return -1; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c index f23517a62c0..dcd4f8e53f5 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/TLS/tls_lib.c @@ -68,7 +68,9 @@ static uint8_t tls_parse_server_key_exchange(uint8_t *ptr, uint16_t len, sec_sui static uint8_t *tls_set_client_key_excange(uint8_t *ptr, sec_suite_t *tls_suite); static uint8_t tls_parse_server_hello(uint8_t *ptr, sec_suite_t *tls_suite); +#ifdef PANA_SERVER_API static uint8_t tls_parse_client_hello(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suite); +#endif static tls_psk_key_t *tls_get_key(uint16_t key_id); tls_session_t *amr_tls_session_allocate(void) @@ -171,7 +173,7 @@ void tls_finnish_copy(uint8_t *ptr, tls_heap_t *heap_ptr) } -uint8_t tls_parse_client_hello(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suite) +static uint8_t tls_parse_client_hello(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suite) { uint8_t ret_val = 0, i = 0; uint16_t tls_version; @@ -548,6 +550,7 @@ uint8_t tls_parse_server_key_exchange(uint8_t *ptr, uint16_t len, sec_suite_t *t return 0; } +#ifdef ECC static uint8_t tls_parse_client_key_exchange(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suite) { (void)len; @@ -567,6 +570,7 @@ static uint8_t tls_parse_client_key_exchange(uint8_t *ptr, uint16_t len, sec_sui return 0; } +#endif void tls_read_certi_signature(tls_heap_t *theap, uint8_t certificate) @@ -589,8 +593,8 @@ void tls_read_certi_signature(tls_heap_t *theap, uint8_t certificate) } - -uint8_t tls_parse_certificate_verify(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suite) +#ifdef ECC +static uint8_t tls_parse_certificate_verify(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suite) { (void)len; uint16_t sig_algh, sig_len; @@ -653,7 +657,7 @@ uint8_t tls_parse_certificate_verify(uint8_t *ptr, uint16_t len, sec_suite_t *tl } return 1; } - +#endif tls_ecc_heap_t *ecc_allocate_ram(void) { @@ -1690,6 +1694,7 @@ buffer_t *tls_server_up(buffer_t *buf, sec_suite_t *tls_suite) buf = tls_certificate_buffer_store(buf, certi_rx, tls_suite); } #else + (void)tls_suite; if (buf) { buf = buffer_free(buf); } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c index 19be4a7f7a3..296f76362d5 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c @@ -100,7 +100,7 @@ static uint8_t kmp_instance_identifier = 0; static kmp_msg_if_entry_t *kmp_api_msg_if_get(kmp_service_t *service, uint8_t msg_if_instance_id); static void kmp_api_sec_prot_create_confirm(sec_prot_t *prot, sec_prot_result_e result); static void kmp_api_sec_prot_create_indication(sec_prot_t *prot); -static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); +static bool kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); static void kmp_api_sec_prot_finished(sec_prot_t *prot); static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size); static int8_t kmp_sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags); @@ -234,10 +234,10 @@ static void kmp_api_sec_prot_create_indication(sec_prot_t *prot) kmp->create_ind((kmp_api_t *)kmp, kmp->type, kmp->addr); } -static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) +static bool kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); - kmp->finished_ind((kmp_api_t *)kmp, (kmp_result_e) result, sec_keys); + return kmp->finished_ind((kmp_api_t *)kmp, (kmp_result_e) result, sec_keys); } static void kmp_api_sec_prot_finished(sec_prot_t *prot) @@ -598,8 +598,7 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, k int8_t ret = -1; if (kmp->sec_prot.receive != NULL) { ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size); - } - if (kmp->sec_prot.conn_receive != NULL) { + } else if (kmp->sec_prot.conn_receive != NULL) { ret = kmp->sec_prot.conn_receive(&kmp->sec_prot, pdu, size, connection_num); } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h index fa945eb4805..3c880de2921 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h @@ -49,8 +49,8 @@ typedef enum { typedef enum { KMP_RESULT_OK = 0, // Successful KMP_RESULT_ERR_NO_MEM = -1, // No memory - KMP_RESULT_ERR_TX_NO_ACK = -2, // No acknowledge was received - KMP_RESULT_ERR_UNSPEC = -3 // Other reason + KMP_RESULT_ERR_TX_NO_ACK = -2, // No TX acknowledge was received + KMP_RESULT_ERR_TX_UNSPEC = -3 // Other TX reason } kmp_result_e; typedef enum { @@ -115,8 +115,10 @@ void kmp_api_create_response(kmp_api_t *kmp, kmp_result_e result); * \param result ok or fail * \param sec_keys security keys * + * \return TRUE authentication has been completed, FALSE authentication continues + * */ -typedef void kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); +typedef bool kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); /** * kmp_api_finished will be called when KMP has finished and is ready for delete diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c index 84d3c013fa0..122cfe4e023 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -89,7 +89,7 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot); static int8_t auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot); -static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); +static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state, bool retry); static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); static int8_t auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot); @@ -247,7 +247,7 @@ static int8_t auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot) return eap_tls_sec_prot_lib_message_handle(data_ptr, length, new_seq_id, &data->tls_send, &data->tls_recv); } -static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state) +static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state, bool retry) { eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -275,9 +275,9 @@ static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c return -1; } - tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[eap_code - 1], - eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size, - trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: %s %s type %s id %i flags %x len %i, eui-64: %s", retry ? "retry" : "send", + eap_msg_trace[eap_code - 1], eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", + data->eap_id_seq, flags, eapol_pdu_size, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) { return -1; @@ -305,13 +305,13 @@ static void auth_eap_tls_sec_prot_tls_create_indication(sec_prot_t *tls_prot) tls_prot->create_resp(tls_prot, SEC_RESULT_OK); } -static void auth_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) +static bool auth_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) { (void) sec_keys; sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); if (!prot) { - return; + return false; } eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -333,6 +333,8 @@ static void auth_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, // On fatal error terminate right away prot->state_machine_call(prot); } + + return false; } static int8_t auth_eap_tls_sec_prot_tls_send(sec_prot_t *tls_prot, void *pdu, uint16_t size) @@ -418,7 +420,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_seq_id_update(prot); // Sends EAP request, Identity - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE, false); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -432,7 +434,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { // Re-sends EAP request, Identity - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE, true); return; } @@ -442,7 +444,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } // Sends EAP request, TLS EAP start - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START, false); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -456,12 +458,13 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { + if (sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_START) { // Re-sends EAP request, TLS EAP start - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START, true); } else { // Re-sends EAP request, TLS EAP - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING, true); } return; } @@ -475,7 +478,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } if (result == EAP_TLS_MSG_IDENTITY) { // If received EAP response, Identity: re-sends EAP request, TLS EAP start - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START, true); return; } @@ -524,7 +527,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) data->send_pending = false; // Sends EAP request, TLS EAP, TLS exchange - auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING, false); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -534,10 +537,10 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // Supplicant PMK is now valid sec_prot_keys_pmk_mismatch_reset(prot->sec_keys); // Sends EAP success - auth_eap_tls_sec_prot_message_send(prot, EAP_SUCCESS, 0, EAP_TLS_EXCHANGE_NONE); + auth_eap_tls_sec_prot_message_send(prot, EAP_SUCCESS, 0, EAP_TLS_EXCHANGE_NONE, false); } else { // Sends EAP failure - auth_eap_tls_sec_prot_message_send(prot, EAP_FAILURE, 0, EAP_TLS_EXCHANGE_NONE); + auth_eap_tls_sec_prot_message_send(prot, EAP_FAILURE, 0, EAP_TLS_EXCHANGE_NONE, false); sec_prot_result_set(&data->common, SEC_RESULT_ERROR); } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index 8e0952c1621..3384716879e 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -295,13 +295,13 @@ static void supp_eap_tls_sec_prot_tls_create_confirm(sec_prot_t *tls_prot, sec_p } } -static void supp_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) +static bool supp_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) { (void) sec_keys; sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); if (!prot) { - return; + return false; } eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -324,6 +324,8 @@ static void supp_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, // On fatal error and on success calls state machine to sent empty EAP-TLS message prot->state_machine_call(prot); } + + return false; } static int8_t supp_eap_tls_sec_prot_tls_send(sec_prot_t *tls_prot, void *pdu, uint16_t size) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index 1162eb9c356..ec89a9a09e4 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -80,7 +80,8 @@ static int8_t auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot); -static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg); +static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg, bool retry); +static int8_t auth_fwh_sec_prot_auth_completed_send(sec_prot_t *prot); static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys); @@ -204,7 +205,7 @@ static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, return msg; } -static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg) +static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg, bool retry) { fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); @@ -301,7 +302,9 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ return -1; } - tr_info("4WH: send %s, eui-64: %s", msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("4WH: %s %s, eui-64: %s", retry ? "retry" : "send", + msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3", + trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { return -1; @@ -310,6 +313,18 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ return 0; } +static int8_t auth_fwh_sec_prot_auth_completed_send(sec_prot_t *prot) +{ + uint8_t *eapol_pdu_frame = ns_dyn_mem_temporary_alloc(prot->header_size); + + // Send zero length message to relay which requests LLC to remove EAPOL temporary entry based on EUI-64 + if (prot->send(prot, eapol_pdu_frame, prot->header_size) < 0) { + return -1; + } + + return 0; +} + static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); @@ -347,7 +362,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) // Sends 4WH Message 1 sec_prot_lib_nonce_generate(data->nonce); - auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); + auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1, false); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -360,7 +375,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) if (sec_prot_result_timeout_check(&data->common)) { // Re-sends 4WH Message 1 sec_prot_lib_nonce_generate(data->nonce); - auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); + auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1, true); } else { if (data->recv_msg != FWH_MESSAGE_2) { return; @@ -375,7 +390,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) } // Sends 4WH Message 3 - auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); + auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3, false); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -388,7 +403,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) case FWH_STATE_MESSAGE_4: if (sec_prot_result_timeout_check(&data->common)) { // Re-sends 4WH Message 3 - auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); + auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3, true); } else { if (data->recv_msg != FWH_MESSAGE_4) { return; @@ -416,7 +431,11 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) tr_info("4WH: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // KMP-FINISHED.indication, - prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); + if (prot->finished_ind(prot, sec_prot_result_get(&data->common), 0)) { + // Authentication completed (all GTKs inserted) + auth_fwh_sec_prot_auth_completed_send(prot); + } + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); break; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index d1101d2292e..4424b55a2c6 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -71,7 +71,8 @@ static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot); -static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg); +static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg, bool retry); +static int8_t auth_gkh_sec_prot_auth_completed_send(sec_prot_t *prot); static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot); @@ -180,7 +181,7 @@ static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, return msg; } -static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg) +static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg, bool retry) { uint16_t kde_len = 0; @@ -249,7 +250,8 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_ return -1; } - tr_info("GKH: send Message 1, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("GKH: %s Message 1, eui-64: %s", retry ? "retry" : "send", + trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { return -1; @@ -258,6 +260,18 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_ return 0; } +static int8_t auth_gkh_sec_prot_auth_completed_send(sec_prot_t *prot) +{ + uint8_t *eapol_pdu_frame = ns_dyn_mem_temporary_alloc(prot->header_size); + + // Send zero length message to relay which requests LLC to remove EAPOL temporary entry based on EUI-64 + if (prot->send(prot, eapol_pdu_frame, prot->header_size) < 0) { + return -1; + } + + return 0; +} + static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); @@ -287,7 +301,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) prot->create_conf(prot, SEC_RESULT_OK); // Sends GKH Message 1 - auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); + auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1, false); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -303,7 +317,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) if (sec_prot_result_timeout_check(&data->common)) { // Re-sends GKH Message 1 - auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); + auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1, true); } else { if (auth_gkh_sec_prot_mic_validate(prot) < 0) { return; @@ -319,7 +333,10 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) tr_info("GKH finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // KMP-FINISHED.indication, - prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); + if (prot->finished_ind(prot, sec_prot_result_get(&data->common), 0)) { + // Authentication completed (all GTKs inserted) + auth_gkh_sec_prot_auth_completed_send(prot); + } sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED); break; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c index ec3600e84cf..6467839c46b 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -324,7 +324,7 @@ static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e 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, SEC_RESULT_ERR_UNSPEC); + sec_prot_result_set(&data->common, SEC_RESULT_ERR_TX_UNSPEC); } prot->state_machine_call(prot); return 0; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h index 565ad5148a5..ac283a00c18 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h @@ -31,7 +31,7 @@ typedef enum { SEC_RESULT_OK = 0, SEC_RESULT_ERR_NO_MEM = -1, SEC_RESULT_ERR_TX_NO_ACK = -2, - SEC_RESULT_ERR_UNSPEC = -3, + SEC_RESULT_ERR_TX_UNSPEC = -3, SEC_RESULT_TIMEOUT = -4, SEC_RESULT_ERROR = -5, SEC_RESULT_CONF_ERROR = -6, @@ -106,8 +106,10 @@ typedef void sec_prot_create_indication(sec_prot_t *prot); * \param result result * \param sec_keys security keys * + * \return TRUE authentication has been completed, FALSE authentication continues + * */ -typedef void sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); +typedef bool sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); /** * sec_prot_finished Security protocol has finished and is ready for delete diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h index dd75e2c226d..17efc2b5894 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h @@ -23,10 +23,11 @@ typedef struct sec_prot_cfg_s { trickle_params_t sec_prot_trickle_params; uint16_t sec_prot_retry_timeout; - uint16_t sec_max_ongoing_authentication; uint16_t initial_key_retry_delay; trickle_params_t initial_key_trickle_params; uint8_t initial_key_retry_cnt; + uint8_t max_ongoing_auth_constant; + uint16_t max_ongoing_auth_size_scaler; } sec_prot_cfg_t; /* Security timer configuration settings */ @@ -53,9 +54,14 @@ typedef struct sec_radius_cfg_s { bool radius_addr_set : 1; /**< Radius server address is set */ } sec_radius_cfg_t; +typedef struct sec_timing_cfg_s { + uint16_t temp_eapol_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 330 */ +} sec_timing_cfg_t; + typedef struct sec_cfg_s { sec_prot_cfg_t prot_cfg; sec_timer_cfg_t timer_cfg; + sec_timing_cfg_t timing_cfg; sec_radius_cfg_t *radius_cfg; } sec_cfg_t; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_configuration_interface.c b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_configuration_interface.c index 5ac0f81a4e7..df247c80b51 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_configuration_interface.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_configuration_interface.c @@ -140,6 +140,15 @@ int ns_fhss_ws_set_hop_count(const fhss_api_t *fhss_api, const uint8_t hop_count return fhss_ws_set_hop_count(fhss_structure, hop_count); } +int ns_fhss_ws_set_tx_allowance_level(const fhss_api_t *fhss_api, const fhss_ws_tx_allow_level global_level, const fhss_ws_tx_allow_level ef_level) +{ + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure || !fhss_structure->ws) { + return -1; + } + return fhss_ws_set_tx_allowance_level(fhss_structure, global_level, ef_level); +} + int ns_fhss_statistics_start(const fhss_api_t *fhss_api, fhss_statistics_t *fhss_statistics) { fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c index 11b0ff28d88..6c4e62e0d99 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c @@ -84,6 +84,8 @@ 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 void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay); static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure); +static bool fhss_allow_transmitting_on_rx_slot(fhss_structure_t *fhss_structure); +static bool fhss_allow_unicast_on_broadcast_channel(fhss_structure_t *fhss_structure); static int32_t fhss_channel_index_from_mask(const uint32_t *channel_mask, int32_t channel_index, uint16_t number_of_channels); // This function supports rounding up @@ -167,6 +169,10 @@ fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configurati 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; + // By default, allow transmitting unicast data only on TX slots. + fhss_struct->ws->tx_level = WS_TX_SLOT; + // By default, allow always transmitting unicast data in expedited forwarding mode. + fhss_struct->ws->ef_tx_level = WS_TX_ALWAYS; ns_list_init(&fhss_struct->fhss_failed_tx_list); return fhss_struct; } @@ -302,12 +308,13 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) if (!fhss_structure) { return; } - + platform_enter_critical(); if (fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval == 0 || fhss_structure->ws->fhss_configuration.fhss_broadcast_interval == 0) { // stop broadcast schedule fhss_structure->ws->is_on_bc_channel = false; fhss_structure->ws->synchronization_time = 0; fhss_structure->ws->broadcast_timer_running = false; + platform_exit_critical(); return; } @@ -340,6 +347,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) fhss_structure->ws->is_on_bc_channel = false; } delay_us %= MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval); + delay_us %= MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval); } if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) { @@ -347,19 +355,22 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) } if (fhss_structure->ws->is_on_bc_channel == false) { - fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (delay_us * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler); + fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - ((int64_t) delay_us * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler); fhss_structure->ws->is_on_bc_channel = true; next_channel = fhss_structure->ws->bc_channel = fhss_ws_calc_bc_channel(fhss_structure); - - /* Start timer with random timeout to trigger broadcast TX queue poll event. - * Min random is 1/50 of the channel dwell interval. - * Max random is 3/4 of the channel dwell interval. - * Event timer resolution is 50us. - */ - uint32_t bc_dwell_us = MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval); - uint16_t bc_min_random = (bc_dwell_us / 50) / 50; - uint16_t bc_max_random = (bc_dwell_us - (bc_dwell_us / 4)) / 50; - eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(bc_min_random, bc_max_random)); + if (fhss_structure->ws->expedited_forwarding_enabled_us) { + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, EXPEDITED_FORWARDING_POLL_PERIOD); + } else { + /* Start timer with random timeout to trigger broadcast TX queue poll event. + * Min random is 1/50 of the channel dwell interval. + * Max random is 3/4 of the channel dwell interval. + * Event timer resolution is 50us. + */ + uint32_t bc_dwell_us = MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval); + uint16_t bc_min_random = (bc_dwell_us / 50) / 50; + uint16_t bc_max_random = (bc_dwell_us - (bc_dwell_us / 4)) / 50; + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(bc_min_random, bc_max_random)); + } } else { fhss_structure->ws->unicast_start_time_us = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); uint32_t timeout = MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval); @@ -367,27 +378,31 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) fhss_structure->ws->is_on_bc_channel = false; // Should return to own (unicast) listening channel after broadcast channel next_channel = fhss_structure->rx_channel; - /* Start timer with random timeout to trigger unicast TX queue poll event. - * For hops 0,1,4,5,8,9,... - * Min random is 1/100 of the TX slot length. - * Max random is 1/5 of the TX slot length. - * - * For hops 2,3,6,7,10,11,... - * Min random is 1/100 of the TX slot length plus 0.5*TX slot length. - * Max random is 1/10 of the TX slot length plus 0.5*TX slot length. - * Event timer resolution is 50us. - */ - // returns 1 if polling of TX queue is done on latter half of the TX slot - uint8_t own_tx_trig_slot = calc_own_tx_trig_slot(fhss_structure->own_hop); - uint32_t txrx_slot_length_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms); - uint16_t uc_min_random = (((txrx_slot_length_us / 2) * own_tx_trig_slot) / 50) + ((txrx_slot_length_us / 100) / 50); - uint16_t uc_max_random = (((txrx_slot_length_us / 2) * own_tx_trig_slot) / 50) + ((txrx_slot_length_us / 5) / 50); - bool tx_allowed = fhss_ws_check_tx_allowed(fhss_structure); - if (!tx_allowed) { - uc_min_random += (txrx_slot_length_us) / 50; - uc_max_random += (txrx_slot_length_us) / 50; + if (fhss_structure->ws->expedited_forwarding_enabled_us) { + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, EXPEDITED_FORWARDING_POLL_PERIOD); + } else { + /* Start timer with random timeout to trigger unicast TX queue poll event. + * For hops 0,1,4,5,8,9,... + * Min random is 1/100 of the TX slot length. + * Max random is 1/5 of the TX slot length. + * + * For hops 2,3,6,7,10,11,... + * Min random is 1/100 of the TX slot length plus 0.5*TX slot length. + * Max random is 1/10 of the TX slot length plus 0.5*TX slot length. + * Event timer resolution is 50us. + */ + // returns 1 if polling of TX queue is done on latter half of the TX slot + uint8_t own_tx_trig_slot = calc_own_tx_trig_slot(fhss_structure->own_hop); + uint32_t txrx_slot_length_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms); + uint16_t uc_min_random = (((txrx_slot_length_us / 2) * own_tx_trig_slot) / 50) + ((txrx_slot_length_us / 100) / 50); + uint16_t uc_max_random = (((txrx_slot_length_us / 2) * own_tx_trig_slot) / 50) + ((txrx_slot_length_us / 5) / 50); + bool tx_allowed = fhss_ws_check_tx_allowed(fhss_structure); + if (!tx_allowed) { + uc_min_random += (txrx_slot_length_us) / 50; + uc_max_random += (txrx_slot_length_us) / 50; + } + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(uc_min_random, uc_max_random)); } - eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(uc_min_random, uc_max_random)); #ifdef FHSS_CHANNEL_DEBUG tr_info("%"PRIu32" UC %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), fhss_structure->rx_channel); @@ -409,6 +424,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) tr_info("%u BC_done", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api)); } #endif + platform_exit_critical(); } static int own_floor(float value) @@ -435,19 +451,35 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots) return; } - if (fhss_structure->ws->is_on_bc_channel == true) { - queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true); - } else { - // On unicast, start timer to trigger polling event on next TX slot - uint32_t delay_between_tx_slots_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms) * 2; - // Timer could drift to RX slot when broadcast interval is high. Return timer to TX slot. - if (fhss_ws_check_tx_allowed(fhss_structure) == false) { - delay_between_tx_slots_us -= MS_TO_US(fhss_structure->ws->txrx_slot_length_ms - (calc_own_tx_trig_slot(fhss_structure->own_hop) * (fhss_structure->ws->txrx_slot_length_ms / 2))); + if (fhss_structure->ws->expedited_forwarding_enabled_us) { + if ((fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api) - fhss_structure->ws->expedited_forwarding_enabled_us) > S_TO_US(EXPEDITED_FORWARDING_PERIOD)) { + fhss_structure->ws->expedited_forwarding_enabled_us = 0; } - if (delay_between_tx_slots_us < get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval))) { - eventOS_callback_timer_start(fhss_structure->fhss_event_timer, delay_between_tx_slots_us / 50); + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, EXPEDITED_FORWARDING_POLL_PERIOD); + if (fhss_structure->ws->is_on_bc_channel == true) { + queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true); + } else { + queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false); } + } else if ((fhss_structure->ws->unicast_timer_running == false) && (fhss_structure->ws->broadcast_timer_running == false)) { + // No one would poll TX queue if schedule timers were not started. Start poll timer with default interval. + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, DEFAULT_POLL_PERIOD); queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false); + } else { + if (fhss_structure->ws->is_on_bc_channel == true) { + queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true); + } else { + // On unicast, start timer to trigger polling event on next TX slot + uint32_t delay_between_tx_slots_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms) * 2; + // Timer could drift to RX slot when broadcast interval is high. Return timer to TX slot. + if (fhss_ws_check_tx_allowed(fhss_structure) == false) { + delay_between_tx_slots_us -= MS_TO_US(fhss_structure->ws->txrx_slot_length_ms - (calc_own_tx_trig_slot(fhss_structure->own_hop) * (fhss_structure->ws->txrx_slot_length_ms / 2))); + } + if (delay_between_tx_slots_us < get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval))) { + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, delay_between_tx_slots_us / 50); + } + queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false); + } } if (queue_size) { fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); @@ -526,6 +558,16 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat if (!fhss_structure) { return -1; } + if (fhss_state == FHSS_EXPEDITED_FORWARDING) { + if (!fhss_structure->ws->expedited_forwarding_enabled_us) { + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, EXPEDITED_FORWARDING_POLL_PERIOD); + } + fhss_structure->ws->expedited_forwarding_enabled_us = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); + if (!fhss_structure->ws->expedited_forwarding_enabled_us) { + fhss_structure->ws->expedited_forwarding_enabled_us++; + } + return 0; + } 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; @@ -617,12 +659,15 @@ static int fhss_ws_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_a if (is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == false)) { return -3; } - // Do not allow unicast destination on broadcast channel + // Do not allow unicast destination on broadcast channel unless it is specifically enabled if (!is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true)) { - return -1; + if (fhss_allow_unicast_on_broadcast_channel(fhss_structure)) { + return 0; + } + return -3; } // Check TX/RX slot - if (!fhss_ws_check_tx_allowed(fhss_structure)) { + if (!fhss_allow_transmitting_on_rx_slot(fhss_structure) && !fhss_ws_check_tx_allowed(fhss_structure)) { return -1; } if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) { @@ -737,6 +782,30 @@ static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_ #endif } +static bool fhss_allow_transmitting_on_rx_slot(fhss_structure_t *fhss_structure) +{ + if (fhss_structure->ws->tx_level >= WS_TX_AND_RX_SLOT) { + return true; + } + // This is allowed only for devices in expedited forwarding mode + if (fhss_structure->ws->expedited_forwarding_enabled_us && (fhss_structure->ws->ef_tx_level >= WS_TX_AND_RX_SLOT)) { + return true; + } + return false; +} + +static bool fhss_allow_unicast_on_broadcast_channel(fhss_structure_t *fhss_structure) +{ + if (fhss_structure->ws->tx_level >= WS_TX_ALWAYS) { + return true; + } + // This is allowed only for devices in expedited forwarding mode + if (fhss_structure->ws->expedited_forwarding_enabled_us && (fhss_structure->ws->ef_tx_level >= WS_TX_ALWAYS)) { + return true; + } + return false; +} + 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) { (void) frame_type; @@ -748,8 +817,8 @@ static bool fhss_ws_check_tx_conditions_callback(const fhss_api_t *api, bool is_ if (is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == false)) { return false; } - // Do not allow unicast destination on broadcast channel - if (!is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true)) { + // Do not allow unicast destination on broadcast channel unless it is specifically enabled + if (!is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true) && !fhss_allow_unicast_on_broadcast_channel(fhss_structure)) { return false; } // This condition will check that message is not sent on bad channel @@ -761,7 +830,7 @@ static bool fhss_ws_check_tx_conditions_callback(const fhss_api_t *api, bool is_ return false; } // Check TX/RX slot for unicast frames - if (!is_broadcast_addr && !fhss_ws_check_tx_allowed(fhss_structure)) { + if (!is_broadcast_addr && !fhss_allow_transmitting_on_rx_slot(fhss_structure) && !fhss_ws_check_tx_allowed(fhss_structure)) { return false; } return true; @@ -923,6 +992,10 @@ static uint32_t fhss_ws_get_retry_period_callback(const fhss_api_t *api, uint8_t if (fhss_structure->ws->is_on_bc_channel == true) { return return_value; } + // No need to wait until TX slot when sending on RX slot is allowed + if (fhss_allow_transmitting_on_rx_slot(fhss_structure) == true) { + return return_value; + } uint32_t txrx_slot_length_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms); uint32_t unicast_start_us = fhss_structure->ws->unicast_start_time_us; @@ -955,6 +1028,7 @@ static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay) if (!fhss_structure) { return; } + platform_enter_critical(); int32_t delay_us = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api) - fhss_structure->ws->next_uc_timeout; if (!fhss_structure->ws->uc_slot && !fhss_structure->ws->next_uc_timeout) { delay_us = 0; @@ -974,6 +1048,7 @@ static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay) if (!timeout) { fhss_stop_timer(fhss_structure, fhss_unicast_handler); fhss_structure->ws->unicast_timer_running = false; + platform_exit_critical(); return; } fhss_ws_start_timer(fhss_structure, timeout - (delay_us * fhss_structure->platform_functions.fhss_resolution_divider), fhss_unicast_handler); @@ -985,6 +1060,7 @@ static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay) fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); } } + platform_exit_critical(); } int fhss_ws_set_callbacks(fhss_structure_t *fhss_structure) @@ -1018,6 +1094,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], return 0; } platform_enter_critical(); + uint16_t own_bc_slot = fhss_structure->ws->bc_slot; uint32_t prev_synchronization_time = fhss_structure->ws->synchronization_time; fhss_structure->ws->synchronization_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); @@ -1126,6 +1203,11 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co channel_count_uc = channel_count_bc; } + // No one would poll TX queue if schedule timers were not started. Start poll timer with default interval. + if ((fhss_structure->ws->unicast_timer_running == false) && (fhss_structure->ws->broadcast_timer_running == false)) { + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, DEFAULT_POLL_PERIOD); + } + fhss_structure->number_of_channels = fhss_configuration->channel_mask_size; fhss_structure->number_of_bc_channels = channel_count_bc; fhss_structure->number_of_uc_channels = channel_count_uc; @@ -1156,4 +1238,11 @@ int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_co return 0; } +int fhss_ws_set_tx_allowance_level(fhss_structure_t *fhss_structure, const fhss_ws_tx_allow_level global_level, const fhss_ws_tx_allow_level ef_level) +{ + fhss_structure->ws->tx_level = global_level; + fhss_structure->ws->ef_tx_level = ef_level; + return 0; +} + #endif // HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h index c81bac463ee..6e3b3d5d482 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.h @@ -18,17 +18,23 @@ #define FHSS_WS_H_ // TX slot length is optimised to this packet length -#define OPTIMAL_PACKET_LENGTH 500 +#define OPTIMAL_PACKET_LENGTH 500 // Max TX/RX slot length in milliseconds. Is used when datarate is not given by PHY or calculated slot length exceeds maximum allowed. -#define WS_TXRX_SLOT_LEN_MS_MAX 100 +#define WS_TXRX_SLOT_LEN_MS_MAX 100 // Min TX/RX slot length in milliseconds. Is used when calculated slot length is under minimum allowed. -#define WS_TXRX_SLOT_LEN_MS_MIN 10 +#define WS_TXRX_SLOT_LEN_MS_MIN 13 // Default minimum broadcast synchronization interval in seconds -#define DEFAULT_MIN_SYNCH_INTERVAL 60 +#define DEFAULT_MIN_SYNCH_INTERVAL 60 // Drift compensation allowed if at least SYNCH_COMPENSATION_MIN_INTERVAL (seconds) since last synchronization -#define SYNCH_COMPENSATION_MIN_INTERVAL 60 +#define SYNCH_COMPENSATION_MIN_INTERVAL 60 // MAX compensation per received synchronization info in ns -#define MAX_DRIFT_COMPENSATION_STEP 10 +#define MAX_DRIFT_COMPENSATION_STEP 10 +// Length of expedited forwarding period in seconds +#define EXPEDITED_FORWARDING_PERIOD 5 +// TX poll interval for expedited forwarding in 50us slots +#define EXPEDITED_FORWARDING_POLL_PERIOD (5000 / 50) +// TX poll interval used when channel schedules are not yet started (50us slots) +#define DEFAULT_POLL_PERIOD (10000 / 50) typedef struct fhss_ws fhss_ws_t; struct fhss_ws { @@ -44,9 +50,12 @@ struct fhss_ws { uint8_t *tr51_output_table; uint32_t next_uc_timeout; uint32_t next_bc_timeout; + uint32_t expedited_forwarding_enabled_us; bool unicast_timer_running; bool broadcast_timer_running; bool is_on_bc_channel; + fhss_ws_tx_allow_level tx_level; + fhss_ws_tx_allow_level ef_tx_level; struct fhss_ws_configuration fhss_configuration; const struct broadcast_timing_info *parent_bc_info; fhss_get_neighbor_info *get_neighbor_info; @@ -58,6 +67,7 @@ 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); +int fhss_ws_set_tx_allowance_level(fhss_structure_t *fhss_structure, const fhss_ws_tx_allow_level global_level, const fhss_ws_tx_allow_level ef_level); void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure); #endif /*FHSS_WS_H_*/ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws_empty_functions.c b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws_empty_functions.c index 11896b55c24..4a68275472e 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws_empty_functions.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws_empty_functions.c @@ -80,5 +80,14 @@ int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_co return -1; } +int fhss_ws_set_tx_allowance_level(fhss_structure_t *fhss_structure, const fhss_ws_tx_allow_level global_level, const fhss_ws_tx_allow_level ef_level) +{ + (void) fhss_structure; + (void) global_level; + (void) ef_level; + + return -1; +} + #endif // HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/nd_proxy/nd_proxy.h b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/nd_proxy/nd_proxy.h index b92ead820ea..004d10f325d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/nd_proxy/nd_proxy.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/nd_proxy/nd_proxy.h @@ -142,9 +142,9 @@ bool nd_proxy_upstream_route_onlink(int8_t downstream_id, uint8_t *address); NS_DUMMY_DEFINITIONS_OK #define nd_proxy_downstream_interface_register(interface_id, nd_proxy_req, bridge_state_update) -1 -#define nd_proxy_downstream_interface_unregister(interface_id) -1 -#define nd_proxy_upstream_interface_register(interface_id, route_validation_req) -1 -#define nd_proxy_upstream_interface_unregister(interface_id) -1 +#define nd_proxy_downstream_interface_unregister(interface_id) (-1) +#define nd_proxy_upstream_interface_register(interface_id, route_validation_req) (-1) +#define nd_proxy_upstream_interface_unregister(interface_id) (-1) #define nd_proxy_enabled_for_downstream(interface_id) false #define nd_proxy_enabled_for_upstream(interface_id) false #define nd_proxy_target_address_validation(upstream_id, address) false diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/utils/ns_conf.c b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/utils/ns_conf.c index b2e0f26d152..affc32cc8be 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/utils/ns_conf.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/utils/ns_conf.c @@ -24,10 +24,10 @@ int ns_conf_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical) { - return ns_monitor_heap_gc_threshold_set(percentage_high, percentage_critical); + return ns_monitor_heap_gc_threshold_set(0, 0, percentage_high, 0, 0, percentage_critical); } int ns_conf_packet_ingress_rate_limit_by_mem(uint8_t free_heap_percentage) { - return ns_monitor_packet_ingress_rate_limit_by_memory(free_heap_percentage); + return ns_monitor_packet_ingress_rate_limit_by_memory(0, 0, free_heap_percentage); } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.c b/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.c index 711159c4d57..0cbc0a4065d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.c @@ -96,7 +96,7 @@ static NS_LIST_DEFINE(ipv6_routing_table, ipv6_route_t, link); static ipv6_destination_t *ipv6_destination_lookup(const uint8_t *address, int8_t interface_id); static void ipv6_destination_cache_forget_router(ipv6_neighbour_cache_t *cache, const uint8_t neighbour_addr[16]); static void ipv6_destination_cache_forget_neighbour(const ipv6_neighbour_t *neighbour); -static void ipv6_destination_release(ipv6_destination_t *dest); +static bool ipv6_destination_release(ipv6_destination_t *dest); static void ipv6_route_table_remove_router(int8_t interface_id, const uint8_t *addr, ipv6_route_src_t source); static uint16_t total_metric(const ipv6_route_t *route); static uint8_t ipv6_route_table_count_source(int8_t interface_id, ipv6_route_src_t source); @@ -481,6 +481,16 @@ bool ipv6_neighbour_has_registered_by_eui64(ipv6_neighbour_cache_t *cache, const return false; } +ipv6_neighbour_t *ipv6_neighbour_get_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64) +{ + ns_list_foreach_safe(ipv6_neighbour_t, cur, &cache->list) { + if (cur->type != IP_NEIGHBOUR_GARBAGE_COLLECTIBLE && memcmp(ipv6_neighbour_eui64(cache, cur), eui64, 8) == 0) { + return cur; + } + } + return NULL; +} + void ipv6_neighbour_set_state(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, ip_neighbour_cache_state_t state) { if (!ipv6_neighbour_state_is_probably_reachable(entry->state) && @@ -863,7 +873,7 @@ void ipv6_destination_cache_print(route_print_fn_t *print_fn) print_fn("Destination Cache:"); ns_list_foreach(ipv6_destination_t, entry, &ipv6_destination_cache) { ROUTE_PRINT_ADDR_STR_BUFFER_INIT(addr_str); - print_fn(" %s (life %u)", ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, entry->destination), entry->lifetime); + print_fn(" %s (%d id) (life %u)", ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, entry->destination), entry->interface_id, entry->lifetime); #ifdef HAVE_IPV6_ND if (entry->redirected) { print_fn(" Redirect %s%%%u", ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, entry->redirect_addr), entry->interface_id); @@ -939,7 +949,6 @@ ipv6_destination_t *ipv6_destination_lookup_or_create(const uint8_t *address, in if (!entry) { if (count > destination_cache_config.max_entries) { entry = ns_list_get_last(&ipv6_destination_cache); - ns_list_remove(&ipv6_destination_cache, entry); ipv6_destination_release(entry); } @@ -1082,18 +1091,31 @@ void ipv6_destination_cache_forced_gc(bool full_gc) **/ ns_list_foreach_reverse_safe(ipv6_destination_t, entry, &ipv6_destination_cache) { if (entry->lifetime == 0 || gc_count > destination_cache_config.long_term_entries || full_gc) { - ns_list_remove(&ipv6_destination_cache, entry); + if (ipv6_destination_release(entry)) { + gc_count--; + } + } + } +} + +void ipv6_destination_cache_clean(int8_t interface_id) +{ + ns_list_foreach_reverse_safe(ipv6_destination_t, entry, &ipv6_destination_cache) { + if (entry->interface_id == interface_id) { ipv6_destination_release(entry); - gc_count--; } } } -static void ipv6_destination_release(ipv6_destination_t *dest) +static bool ipv6_destination_release(ipv6_destination_t *dest) { if (--dest->refcount == 0) { + ns_list_remove(&ipv6_destination_cache, dest); + tr_debug("Destination cache remove: %s", trace_ipv6(dest->destination)); ns_dyn_mem_free(dest); + return true; } + return false; } static void ipv6_destination_cache_gc_periodic(void) @@ -1137,9 +1159,11 @@ static void ipv6_destination_cache_gc_periodic(void) */ ns_list_foreach_reverse_safe(ipv6_destination_t, entry, &ipv6_destination_cache) { if (entry->lifetime == 0 || gc_count > destination_cache_config.short_term_entries) { - ns_list_remove(&ipv6_destination_cache, entry); - ipv6_destination_release(entry); - if (--gc_count <= destination_cache_config.long_term_entries) { + if (ipv6_destination_release(entry)) { + gc_count--; + } + + if (gc_count <= destination_cache_config.long_term_entries) { break; } } @@ -1195,17 +1219,6 @@ static const bool ipv6_route_probing[ROUTE_MAX] = { [ROUTE_RPL_INSTANCE] = true, }; -/* Which route types get minimum link MTU by default */ -/* Makes life easier for tunnel-based systems like RPL */ -static const bool ipv6_route_min_mtu[ROUTE_MAX] = { - [ROUTE_RPL_DAO] = true, - [ROUTE_RPL_DAO_SR] = true, - [ROUTE_RPL_DIO] = true, - [ROUTE_RPL_ROOT] = true, - [ROUTE_RPL_INSTANCE] = true, - [ROUTE_MPL] = true, -}; - // Remember when a route source has deleted an entry - allows buffers still in // event queue to have their route info invalidated. static bool ipv6_route_source_invalidated[ROUTE_MAX]; @@ -1647,7 +1660,7 @@ ipv6_route_t *ipv6_route_add_metric(const uint8_t *prefix, uint8_t prefix_len, i route->info.info = info; route->info.source_id = source_id; route->info.interface_id = interface_id; - route->info.pmtu = ipv6_route_min_mtu[source] ? IPV6_MIN_LINK_MTU : 0xFFFF; + route->info.pmtu = 0xFFFF; if (next_hop) { route->on_link = false; memcpy(route->info.next_hop_addr, next_hop, 16); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.h b/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.h index 944439843e5..ce7eb224762 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/ipv6_stack/ipv6_routing_table.h @@ -162,6 +162,7 @@ extern bool ipv6_neighbour_ll_addr_match(const ipv6_neighbour_t *entry, addrtype extern void ipv6_neighbour_invalidate_ll_addr(ipv6_neighbour_cache_t *cache, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_delete_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); extern bool ipv6_neighbour_has_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); +extern ipv6_neighbour_t *ipv6_neighbour_get_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); extern void ipv6_neighbour_entry_update_unsolicited(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, addrtype_t type, const uint8_t *ll_address/*, bool tentative*/); extern ipv6_neighbour_t *ipv6_neighbour_update_unsolicited(ipv6_neighbour_cache_t *cache, const uint8_t *ip_address, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_reachability_confirmation(const uint8_t ip_address[__static 16], int8_t interface_id); @@ -223,6 +224,7 @@ void ipv6_destination_cache_timer(uint8_t ticks); void ipv6_destination_redirect(const uint8_t *dest_addr, const uint8_t *sender_addr, const uint8_t *redirect_addr, int8_t interface_id, addrtype_t ll_type, const uint8_t *ll_address); #endif void ipv6_destination_cache_forced_gc(bool full_gc); +void ipv6_destination_cache_clean(int8_t interface_id); /* Combined Routing Table (RFC 4191) and Prefix List (RFC 4861) */ /* On-link prefixes have the on_link flag set and next_hop is unset */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c index 66cda2e6d4f..78dddce5ad6 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c @@ -60,6 +60,7 @@ typedef struct { int8_t interface_id; uint8_t server_address[16]; bool relay_activated; + bool add_interface_id_option; ns_list_link_t link; } relay_instance_t; typedef NS_LIST_HEAD(relay_instance_t, link) relay_instance_list_t; @@ -83,6 +84,8 @@ typedef struct { uint8_t *msg_ptr; uint16_t msg_len; uint8_t *relay_start; + uint8_t *opt_interface_id; + uint16_t opt_interface_id_length; ns_list_link_t link; } msg_tr_t; typedef NS_LIST_HEAD(msg_tr_t, link) tr_list_t; @@ -335,6 +338,8 @@ void recv_dhcp_server_msg(void *cb_res) } //Update Source and data msg_tr_ptr->relay_start = msg_ptr; + msg_tr_ptr->opt_interface_id = relay_msg.relay_interface_id.msg_ptr; + msg_tr_ptr->opt_interface_id_length = relay_msg.relay_interface_id.len; memcpy(msg_tr_ptr->addr.address, relay_msg.peer_address, 16); msg_ptr = relay_msg.relay_options.msg_ptr; msg_len = relay_msg.relay_options.len; @@ -408,35 +413,37 @@ void recv_dhcp_relay_msg(void *cb_res) } ns_address_t src_address; - uint8_t relay_frame[DHCPV6_RELAY_LENGTH + 4]; - ns_iovec_t msg_iov[2]; - msg_iov[0].iov_base = relay_frame; - msg_iov[0].iov_len = 34; - msg_iov[1].iov_base = ns_dyn_mem_temporary_alloc(sckt_data->d_len); - msg_iov[1].iov_len = sckt_data->d_len; - if (msg_iov[1].iov_base == NULL) { + //Relay vector added space for relay frame + Interface ID + uint8_t relay_frame[DHCPV6_RELAY_LENGTH + 4 + 5]; + + + uint8_t *socket_data = ns_dyn_mem_temporary_alloc(sckt_data->d_len); + + if (socket_data == NULL) { // read actual message tr_error("Out of resources"); goto cleanup; } + ns_msghdr_t msghdr; + ns_iovec_t msg_data; + msg_data.iov_base = socket_data; + msg_data.iov_len = sckt_data->d_len; //Set messages name buffer msghdr.msg_name = &src_address; msghdr.msg_namelen = sizeof(src_address); - msghdr.msg_iov = &msg_iov[1]; + msghdr.msg_iov = &msg_data; msghdr.msg_iovlen = 1; msghdr.msg_control = NULL; msghdr.msg_controllen = 0; msg_len = socket_recvmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0); - tr_debug("dhcp Relay recv msg"); //Parse type - uint8_t *ptr = msg_iov[1].iov_base; - uint8_t msg_type = *ptr; + uint8_t msg_type = *socket_data; int16_t tc = 0; if (msg_type == DHCPV6_RELAY_FORWARD) { @@ -446,7 +453,7 @@ void recv_dhcp_relay_msg(void *cb_res) } else if (msg_type == DHCPV6_RELAY_REPLY) { //Parse and validate Relay dhcpv6_relay_msg_t relay_msg; - if (!libdhcpv6_relay_msg_read(ptr, msg_len, &relay_msg)) { + if (!libdhcpv6_relay_msg_read(socket_data, msg_len, &relay_msg)) { tr_error("Not valid relay"); goto cleanup; } @@ -458,14 +465,14 @@ void recv_dhcp_relay_msg(void *cb_res) memcpy(src_address.address, relay_msg.peer_address, 16); src_address.type = ADDRESS_IPV6; src_address.identifier = DHCPV6_CLIENT_PORT; - msghdr.msg_iov = &msg_iov[0]; + msghdr.msg_iov = &msg_data; msghdr.msg_iovlen = 1; - msg_iov[0].iov_base = relay_msg.relay_options.msg_ptr; - msg_iov[0].iov_len = relay_msg.relay_options.len; + msg_data.iov_base = relay_msg.relay_options.msg_ptr; + msg_data.iov_len = relay_msg.relay_options.len; tr_debug("Forward Original relay msg to client"); } else { - if (0 != libdhcpv6_message_malformed_check(ptr, msg_len)) { + if (0 != libdhcpv6_message_malformed_check(socket_data, msg_len)) { tr_error("Malformed packet"); goto cleanup; } @@ -476,10 +483,24 @@ void recv_dhcp_relay_msg(void *cb_res) tr_error("No GP address"); goto cleanup; } - + ns_iovec_t msg_iov[2]; + uint8_t *ptr = relay_frame; //Build - libdhcpv6_dhcp_relay_msg_write(relay_frame, DHCPV6_RELAY_FORWARD, 0, src_address.address, gp_address); - libdhcpv6_dhcp_option_header_write(relay_frame + 34, msg_len); + //ADD relay frame vector front of original data + msghdr.msg_iov = &msg_iov[0]; + msg_iov[0].iov_base = relay_frame; + msghdr.msg_iovlen = 2; + //SET Original Data + msg_iov[1].iov_base = socket_data; + msg_iov[1].iov_len = msg_len; + + ptr = libdhcpv6_dhcp_relay_msg_write(ptr, DHCPV6_RELAY_FORWARD, 0, src_address.address, gp_address); + if (relay_srv->add_interface_id_option) { + ptr = libdhcpv6_option_interface_id_write(ptr, sckt_data->interface_id); + } + ptr = libdhcpv6_dhcp_option_header_write(ptr, DHCPV6_OPTION_RELAY, msg_len); + //Update length of relay vector + msg_iov[0].iov_len = ptr - relay_frame; //Update Neighbour table if necessary relay_notify_t *neigh_notify = dhcp_service_notify_find(sckt_data->interface_id); @@ -491,12 +512,6 @@ void recv_dhcp_relay_msg(void *cb_res) memcpy(src_address.address, relay_srv->server_address, 16); src_address.type = ADDRESS_IPV6; src_address.identifier = DHCPV6_SERVER_PORT; - //ADD relay frame vector front of original data - msghdr.msg_iov = &msg_iov[0]; - msghdr.msg_iovlen = 2; - msg_iov[0].iov_base = relay_frame; - msg_iov[0].iov_len = 38; - msg_iov[1].iov_len = msg_len; tr_debug("Forward Client msg to server"); tc = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT; @@ -504,7 +519,7 @@ void recv_dhcp_relay_msg(void *cb_res) socket_setsockopt(sckt_data->socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc)); socket_sendmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0); cleanup: - ns_dyn_mem_free(msg_iov[1].iov_base); + ns_dyn_mem_free(socket_data); return; } @@ -635,6 +650,7 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty relay_srv->instance_id = id; relay_srv->interface_id = interface_id; relay_srv->relay_activated = false; + relay_srv->add_interface_id_option = false; } @@ -655,6 +671,14 @@ void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_addre } } +void dhcp_service_relay_interface_id_option_enable(uint16_t instance, bool enable) +{ + relay_instance_t *relay_srv = dhcp_service_relay_find(instance); + if (relay_srv) { + relay_srv->add_interface_id_option = enable; + } +} + uint8_t *dhcp_service_relay_global_addres_get(uint16_t instance) { relay_instance_t *relay_srv = dhcp_service_relay_find(instance); @@ -851,30 +875,42 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr) //Build Relay Reply only server do this int16_t tc = IP_DSCP_CS6 << IP_TCLASS_DSCP_SHIFT; socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_TCLASS, &tc, sizeof(tc)); - ns_iovec_t data_vector[2]; + ns_iovec_t data_vector[4]; + uint8_t relay_header[4]; + libdhcpv6_dhcp_option_header_write(relay_header, DHCPV6_OPTION_RELAY, msg_tr_ptr->msg_len); ns_msghdr_t msghdr; + msghdr.msg_iovlen = 0; memcpy(msg_tr_ptr->addr.address, msg_tr_ptr->relay_start + 2, 16); msg_tr_ptr->addr.identifier = DHCPV6_SERVER_PORT; //SET IOV vectors //Relay Reply - data_vector[0].iov_base = (void *) msg_tr_ptr->relay_start; - data_vector[0].iov_len = DHCPV6_RELAY_LENGTH + 4; + data_vector[msghdr.msg_iovlen].iov_base = (void *) msg_tr_ptr->relay_start; + data_vector[msghdr.msg_iovlen].iov_len = DHCPV6_RELAY_LENGTH; + msghdr.msg_iovlen++; + if (msg_tr_ptr->opt_interface_id) { + data_vector[msghdr.msg_iovlen].iov_base = (void *)(msg_tr_ptr->opt_interface_id - 4); + data_vector[msghdr.msg_iovlen].iov_len = msg_tr_ptr->opt_interface_id_length + 4; + msghdr.msg_iovlen++; + } + //Relay reply header + data_vector[msghdr.msg_iovlen].iov_base = (void *) relay_header; + data_vector[msghdr.msg_iovlen].iov_len = 4; + msghdr.msg_iovlen++; //DHCPV normal message vector - data_vector[1].iov_base = (void *) msg_tr_ptr->msg_ptr; - data_vector[1].iov_len = msg_tr_ptr->msg_len; + data_vector[msghdr.msg_iovlen].iov_base = (void *) msg_tr_ptr->msg_ptr; + data_vector[msghdr.msg_iovlen].iov_len = msg_tr_ptr->msg_len; + msghdr.msg_iovlen++; //Set message name msghdr.msg_name = (void *) &msg_tr_ptr->addr; msghdr.msg_namelen = sizeof(ns_address_t); msghdr.msg_iov = &data_vector[0]; - msghdr.msg_iovlen = 2; //No ancillary data msghdr.msg_control = NULL; msghdr.msg_controllen = 0; uint8_t *ptr = msg_tr_ptr->relay_start; *ptr = DHCPV6_RELAY_REPLY; - libdhcpv6_dhcp_option_header_write(ptr + 34, msg_tr_ptr->msg_len); retval = socket_sendmsg(msg_tr_ptr->socket, &msghdr, NS_MSG_LEGACY0); } else { @@ -972,6 +1008,12 @@ void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_addre (void)server_address; } +void dhcp_service_relay_interface_id_option_enable(uint16_t instance, bool enable) +{ + (void)instance; + (void)enable; +} + int dhcp_service_send_resp(uint32_t msg_tr_id, uint8_t options, uint8_t *msg_ptr, uint16_t msg_len) { (void)msg_tr_id; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c index 722e41f46e1..abc29b22728 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c @@ -859,9 +859,16 @@ uint8_t *libdhcpv6_dhcp_relay_msg_write(uint8_t *ptr, uint8_t type, uint8_t hop_ return ptr; } -uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t length) +uint8_t *libdhcpv6_option_interface_id_write(uint8_t *ptr, int8_t interface_id) { - ptr = common_write_16_bit(DHCPV6_OPTION_RELAY, ptr); + ptr = libdhcpv6_dhcp_option_header_write(ptr, DHCPV6_OPTION_INTERFACE_ID, 1); + *ptr++ = interface_id; + return ptr; +} + +uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t option_type, uint16_t length) +{ + ptr = common_write_16_bit(option_type, ptr); ptr = common_write_16_bit(length, ptr); return ptr; } @@ -878,6 +885,11 @@ bool libdhcpv6_relay_msg_read(uint8_t *ptr, uint16_t length, dhcpv6_relay_msg_t relay_msg->peer_address = ptr + 16; ptr += 32; //Discover + if (libdhcpv6_message_option_discover(ptr, length - 34, DHCPV6_OPTION_INTERFACE_ID, &relay_msg->relay_interface_id) != 0) { + relay_msg->relay_interface_id.len = 0; + relay_msg->relay_interface_id.msg_ptr = NULL; + } + if (libdhcpv6_message_option_discover(ptr, length - 34, DHCPV6_OPTION_RELAY, &relay_msg->relay_options) != 0) { return false; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h index dd2bd6309fe..5910bab1907 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h @@ -125,6 +125,7 @@ typedef struct dhcpv6_relay_msg { uint8_t hop_limit; uint8_t *link_address; uint8_t *peer_address; + dhcp_options_msg_t relay_interface_id; dhcp_options_msg_t relay_options; } dhcpv6_relay_msg_t; @@ -237,6 +238,7 @@ typedef struct dhcpv6_relay_msg { #define DHCPV6_RELAY_LENGTH 34 #define DHCPV6_OPTION_RELAY 0x0009 +#define DHCPV6_OPTION_INTERFACE_ID 0x0012 @@ -293,7 +295,7 @@ uint16_t libdhcpv6_address_reply_message_len(uint16_t clientDUIDLength, uint16_t uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_duid_options_params_t *serverLink); uint8_t *libdhcpv6_dhcp_relay_msg_write(uint8_t *ptr, uint8_t type, uint8_t hop_limit, uint8_t *peer_addres, uint8_t *link_address); -uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t length); +uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t option_type, uint16_t length); int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params); int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_duid_options_params_t *params); @@ -341,6 +343,8 @@ uint8_t *libdhcpv6_rapid_commit_option_write(uint8_t *ptr); */ uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_t *optionPtr); +uint8_t *libdhcpv6_option_interface_id_write(uint8_t *ptr, int8_t interface_id); + /** diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c index d324c812691..858d2f09318 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c @@ -31,6 +31,8 @@ #ifdef HAVE_DHCPV6_SERVER +#define TRACE_GROUP "dhcp" + static NS_LARGE NS_LIST_DEFINE(dhcpv6_gua_server_list, dhcpv6_gua_server_entry_s, link); bool libdhcpv6_gua_server_list_empty(void) @@ -49,10 +51,9 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void) } entry->serverDynamic_DUID = server_duid_ptr; entry->serverDynamic_DUID_length = 16; - entry->firstFreedId = 0; entry->firstUnusedId = DHCP_ADDRESS_ID_START; - entry->enableAddressAutonous = true; - entry->disableAddressListAllocation = false; + entry->anonymousAddress = false; + entry->disableAddressList = false; entry->maxSupportedClients = 200; entry->validLifetime = 7200; entry->removeCb = NULL; @@ -63,47 +64,34 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void) return entry; } -static uint16_t libdhcpv6_get_next_freed_id(dhcpv6_gua_server_entry_s *serverInfo) +static uint16_t libdhcpv6_get_unique_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; + uint8_t suggested_id = serverInfo->firstUnusedId; + + do { + ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { + if (serverInfo->firstUnusedId == cur->allocatedID) { + serverInfo->firstUnusedId++; + if (serverInfo->firstUnusedId == 0) { + serverInfo->firstUnusedId++; + } + //Start from beginning + break; } - } 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; + } while (suggested_id != serverInfo->firstUnusedId); + //return the first free and increase the value for the next time. + serverInfo->firstUnusedId = suggested_id + 1; + return suggested_id; } 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; + // Unique IDs start to generate from 1 and continue to go up every new address + // if we go around 65535 we start from 1 and search for free id + + return libdhcpv6_get_unique_id(serverInfo); } static void libdhcpv6_gen_suffics_from_eui48(uint8_t *ptr, uint8_t *eui48) @@ -124,93 +112,12 @@ static void libdhcpv6_gen_suffics_from_allocated_id(uint8_t *ptr, uint8_t *serve 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; - memcpy(ptr, serverInfo->guaPrefix, 8); - ptr += 8; - if (serverInfo->enableAddressAutonous) { - if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || - entry->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { - memcpy(ptr, entry->linkId, 8); - *ptr ^= 2; - return 0; - } - - 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) +static void libdhcpv6_address_list_entry_free(dhcpv6_gua_server_entry_s *server_info, dhcpv6_allocated_address_entry_t *entry) { ns_list_remove(&server_info->allocatedAddressList, entry); - if (!server_info->enableAddressAutonous) { - if (entry->allocatedID + 1 == server_info->firstUnusedId) { - server_info->firstUnusedId--; - } else if (server_info->firstFreedId == 0 || server_info->firstFreedId > entry->allocatedID) { - server_info->firstFreedId = entry->allocatedID; - } - } ns_dyn_mem_free(entry); } -void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo) -{ - memcpy(ptr, serverInfo->guaPrefix, 8); - ptr += 8; - if (serverInfo->enableAddressAutonous) { - //Generate address from link layer address - if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || - address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { - memcpy(ptr, address->linkId, 8); - *ptr ^= 2; - return; - } else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { - libdhcpv6_gen_suffics_from_eui48(ptr, address->linkId); - return; - } - } - //Generate from 16-bit allocate and default suffic's - libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, address->allocatedID); -} - -static bool libdhcpv6_address_suffics_compare(const uint8_t *suffics, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo) -{ - uint8_t allocated_suffics[8]; - if (serverInfo->enableAddressAutonous) { - //Generate address from link layer address - if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || - address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { - memcpy(allocated_suffics, address->linkId, 8); - allocated_suffics[0] ^= 2; - goto compare_suffics; - } else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { - libdhcpv6_gen_suffics_from_eui48(allocated_suffics, address->linkId); - goto compare_suffics; - } - } - //Generate from 16-bit allocate and default suffic's - libdhcpv6_gen_suffics_from_allocated_id(allocated_suffics, serverInfo->clientIdDefaultSuffics, address->allocatedID); - -compare_suffics: - if (memcmp(allocated_suffics, suffics, 8)) { - return false; - } - - return true; - -} - - void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds) { //Check All allocated server inside this loop @@ -223,9 +130,9 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds) //Stop use this address for leasequery and delete Route or address map address->preferredLifetime = 0; if (cur->removeCb) { - uint8_t allocated_address[16]; - libdhcpv6_allocated_address_write(allocated_address, address, cur); - cur->removeCb(cur->interfaceId, allocated_address, cur->guaPrefix); + uint8_t ipAddress[16]; + libdhcpv6_allocated_address_write(ipAddress, address, cur); + cur->removeCb(cur->interfaceId, ipAddress, cur->guaPrefix); } } else { address->preferredLifetime -= timeUpdateInSeconds; @@ -233,7 +140,7 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds) } if (address->lifetime <= timeUpdateInSeconds) { - libdhcpv6_address_free(cur, address); + libdhcpv6_address_list_entry_free(cur, address); } else { address->lifetime -= timeUpdateInSeconds; } @@ -337,8 +244,7 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t if (serverInfo) { if ((serverInfo->interfaceId == interfaceId) && (memcmp(serverInfo->guaPrefix, prefix, 8) == 0)) { ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { - ns_list_remove(&serverInfo->allocatedAddressList, cur); - ns_dyn_mem_free(cur); + libdhcpv6_address_list_entry_free(serverInfo, cur); } ns_list_foreach_safe(dhcpv6_dns_server_data_t, cur, &serverInfo->dnsServerList) { @@ -372,7 +278,28 @@ static void libdhcpv6_address_entry_lifetime_set(dhcpv6_allocated_address_entry_ } } -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) +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->anonymousAddress) { + //Generate from 16-bit allocate and default suffic's + libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, address->allocatedID); + return; + } + //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; + } +} + +static void libdhcpv6_generate_address_entry(dhcpv6_allocated_address_t *address, dhcpv6_allocated_address_entry_t *cur, dhcpv6_gua_server_entry_s *serverInfo) { libdhcpv6_allocated_address_write(address->nonTemporalAddress, cur, serverInfo); memcpy(address->linkId, cur->linkId, 8); @@ -384,130 +311,102 @@ static void libdhcpv6_copy_allocated_entry_to_temp(dhcpv6_allocated_address_entr 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) +static void libdhcpv6_address_list_entry_add_to_list(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_entry_t *allocated) { - 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; + if (allocated->allocatedID != 0) { + // If we have allocated ID we sort by it if it is 0 we dont do any sorting + ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { + if (cur->allocatedID > allocated->allocatedID) { + //Add before new allocated + ns_list_add_before(&serverInfo->allocatedAddressList, cur, allocated); + return; + } } } - return NULL; + ns_list_add_to_end(&serverInfo->allocatedAddressList, allocated); } -void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) +void libdhcpv6_address_delete(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) { + uint8_t device_address[16]; 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); + libdhcpv6_allocated_address_write(device_address, cur, serverInfo); + if (memcmp(address, device_address, 16) == 0) { + libdhcpv6_address_list_entry_free(serverInfo, cur); return; } } } - -static void libdhcpv6_address_id_add_to_list(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_entry_t *allocated) +static dhcpv6_allocated_address_entry_t *libdhcpv6_address_list_entry_create(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_entry_t *source) { - 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; - } - } + dhcpv6_allocated_address_entry_t *entry; + + entry = ns_dyn_mem_alloc(sizeof(dhcpv6_allocated_address_entry_t)); + + if (!entry) { + return NULL; } - ns_list_add_to_end(&serverInfo->allocatedAddressList, allocated); + + *entry = *source; + libdhcpv6_address_list_entry_add_to_list(serverInfo, entry); + return entry; } -dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew) +dhcpv6_allocated_address_t *libdhcpv6_address_allocate(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew) { - dhcpv6_allocated_address_t *newEntry = NULL; - dhcpv6_allocated_address_entry_t *allocatedEntry = NULL; + dhcpv6_allocated_address_entry_t newEntry; uint16_t duiLength = 6; if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { duiLength = 8; } - if (serverInfo->enableAddressAutonous && serverInfo->disableAddressListAllocation) { - //Accept allways when autonous - newEntry = &serverInfo->tempAddressEntry; - allocateNew = false; - } - + // Search if we have old address in list 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; - libdhcpv6_address_entry_lifetime_set(cur, serverInfo->validLifetime); - libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo); - return &serverInfo->tempAddressEntry; - } + if (cur->linkType == linkType && memcmp(cur->linkId, linkId, duiLength) == 0) { + cur->iaID = iaID; + cur->T0 = T0; + cur->T1 = T1; + libdhcpv6_address_entry_lifetime_set(cur, serverInfo->validLifetime); + libdhcpv6_generate_address_entry(&serverInfo->tempAddressEntry, cur, serverInfo); + return &serverInfo->tempAddressEntry; } } - if (allocateNew) { - 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 (!allocateNew) { + return NULL; } - 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); - } - } + if (ns_list_count(&serverInfo->allocatedAddressList) >= serverInfo->maxSupportedClients) { + // Maximum supported clients reached + return NULL; + } + + // Generate new address + memcpy(newEntry.linkId, linkId, duiLength); + newEntry.linkType = linkType; + newEntry.iaID = iaID; + newEntry.T0 = T0; + newEntry.T1 = T1; + newEntry.allocatedID = 0; + libdhcpv6_address_entry_lifetime_set(&newEntry, serverInfo->validLifetime); + if (serverInfo->anonymousAddress) { + // Generate anonymous address id + newEntry.allocatedID = libdhcpv6_address_id_allocate(serverInfo); + } + + if (!serverInfo->disableAddressList) { + // Create new List item and add to list + libdhcpv6_address_list_entry_create(serverInfo, &newEntry); } - return newEntry; + libdhcpv6_generate_address_entry(&serverInfo->tempAddressEntry, &newEntry, serverInfo); + return &serverInfo->tempAddressEntry; } dhcpv6_dns_server_data_t *libdhcpv6_dns_server_discover(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h index 3ea3e5f2abb..4dab618b924 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h @@ -59,7 +59,6 @@ typedef struct dhcpv6_vendor_data_s { ns_list_link_t link; /*!< List link entry */ } dhcpv6_vendor_data_t; - typedef struct dhcpv6_allocated_address_s { uint8_t nonTemporalAddress[16]; uint8_t linkId[8]; /*!< Services UL64 */ @@ -71,6 +70,7 @@ typedef struct dhcpv6_allocated_address_s { uint32_t lifetime; } dhcpv6_allocated_address_t; + typedef NS_LIST_HEAD(dhcpv6_allocated_address_entry_t, link) dhcpv6_allocated_address_list_t; typedef NS_LIST_HEAD(dhcpv6_dns_server_data_t, link) dhcpv6_dns_server_list_t; typedef NS_LIST_HEAD(dhcpv6_vendor_data_t, link) dhcpv6_vendor_data_list_t; @@ -85,14 +85,13 @@ 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: 1; - bool disableAddressListAllocation: 1; + bool anonymousAddress: 1; + bool disableAddressList: 1; uint16_t socketInstance_id; uint8_t guaPrefix[8]; uint8_t serverDynamic_DUID_length; 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; @@ -111,12 +110,11 @@ dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t int libdhcpv6_server_duid_set(dhcpv6_gua_server_entry_s *server_info, uint8_t *duid_ptr, uint16_t duid_type, uint8_t duid_length); 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_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); +void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo); +void libdhcpv6_address_delete(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_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); +dhcpv6_allocated_address_t *libdhcpv6_address_allocate(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew); dhcpv6_dns_server_data_t *libdhcpv6_dns_server_discover(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); dhcpv6_dns_server_data_t *libdhcpv6_dns_server_allocate(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); dhcpv6_vendor_data_t *libdhcpv6_vendor_data_discover(dhcpv6_gua_server_entry_s *serverInfo, uint32_t enterprise_number); @@ -127,15 +125,23 @@ uint8_t *libdhcpv6_dns_server_message_writes(dhcpv6_gua_server_entry_s *serverIn uint8_t *libdhcpv6_vendor_data_message_writes(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *ptr); #else #define libdhcpv6_gua_server_list_empty() true -#define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL -#define libdhcpv6_server_data_get_by_prefix_and_socketinstance(socketInstance, prefixPtr) NULL #define libdhcpv6_gua_server_allocate(prefix, interfaceId, serverDUID, serverDUIDType) NULL -#define libdhcpv6_gua_server_free_by_prefix_and_interfaceid(prefix, interfaceId) ((void)0) -#define libdhcpv6_gua_servers_time_update(timeUpdateInSeconds) ((void)0) -#define libdhcpv6_gua_server_free_by_interfaceid(interfaceId) ((void)0) -#define libdhcpv6_address_get_from_allocated_list(serverInfo, address) NULL -#define libdhcpv6_address_rm_from_allocated_list(serverInfo, address) ((void)0) -#define libdhcpv6_address_allocated_list_scan( serverInfo, linkId, linkType, iaID, T0, T1, allocateNew) NULL +#define libdhcpv6_server_duid_set(server_info, duid_ptr, duid_type, duid_length) +#define libdhcpv6_gua_server_free_by_prefix_and_interfaceid(prefix, interfaceId) +#define libdhcpv6_gua_servers_time_update(timeUpdateInSeconds) +#define libdhcpv6_allocated_address_write(ptr, address, serverInfo) +#define libdhcpv6_address_delete(serverInfo, address) +#define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL +#define libdhcpv6_server_data_get_by_prefix_and_socketinstance(socketInstance,prefixPtr) NULL +#define libdhcpv6_address_allocate(serverInfo, euid64, linkType, iaID, T0, T1, allocateNew) NULL +#define libdhcpv6_dns_server_discover(serverInfo, address) NULL +#define libdhcpv6_dns_server_allocate(serverInfo, address) NULL +#define libdhcpv6_vendor_data_discover(serverInfo, enterprise_number) NULL +#define libdhcpv6_vendor_data_allocate(serverInfo, enterprise_number) NULL +#define libdhcpv6_dns_server_message_sizes(serverInfo) 0 +#define libdhcpv6_vendor_data_message_sizes(serverInfo) 0 +#define libdhcpv6_dns_server_message_writes(serverInfo, ptr) NULL +#define libdhcpv6_vendor_data_message_writes(serverInfo, ptr) NULL #endif #endif /* LIBDHCPV6_SERVER_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c index 434bd4d6d39..7975ba89b69 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c @@ -112,10 +112,11 @@ int8_t net_dns_server_address_set(int8_t interface_id, const uint8_t address[16] if (!info_ptr) { info_ptr = dns_server_info_create(interface_id, address); + // Trace only when new entry is created + tr_info("DNS Server: %s from: %s Lifetime: %lu", trace_ipv6(dns_server_address), trace_ipv6(info_ptr->address), (unsigned long) lifetime); } info_ptr->lifetime = lifetime; memcpy(info_ptr->dns_server_address, dns_server_address, 16); - tr_info("DNS Server: %s from: %s Lifetime: %lu", trace_ipv6(info_ptr->dns_server_address), trace_ipv6(info_ptr->address), (unsigned long) info_ptr->lifetime); return 0; } @@ -148,22 +149,22 @@ int8_t net_dns_server_search_list_set(int8_t interface_id, const uint8_t address if (info_ptr->dns_search_list_ptr && info_ptr->dns_search_list_len != dns_search_list_len) { ns_dyn_mem_free(info_ptr->dns_search_list_ptr); info_ptr->dns_search_list_ptr = NULL; + info_ptr->dns_search_list_len = 0; } if (dns_search_list_len) { if (!info_ptr->dns_search_list_ptr) { info_ptr->dns_search_list_ptr = ns_dyn_mem_alloc(dns_search_list_len); + + tr_info("DNS Search List: %s Lifetime: %lu", trace_array(dns_search_list_ptr, dns_search_list_len), (unsigned long) info_ptr->lifetime); } if (!info_ptr->dns_search_list_ptr) { return -2; } memcpy(info_ptr->dns_search_list_ptr, dns_search_list_ptr, dns_search_list_len); + info_ptr->dns_search_list_len = dns_search_list_len; } - - info_ptr->dns_search_list_len = dns_search_list_len; - tr_info("DNS Search List: %s Lifetime: %lu", trace_array(info_ptr->dns_search_list_ptr, info_ptr->dns_search_list_len), (unsigned long) info_ptr->lifetime); - return 0; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c index b863aa29922..09c3fc1b7b3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c @@ -1072,7 +1072,7 @@ int8_t arm_network_certificate_revocation_list_remove(const arm_cert_revocation_ */ int8_t arm_network_key_get(int8_t interface_id, ns_keys_t *key) { -#ifndef PANA +#ifndef PANA_SERVER (void)interface_id; (void)key; #endif @@ -1081,7 +1081,7 @@ int8_t arm_network_key_get(int8_t interface_id, ns_keys_t *key) int8_t arm_pana_server_library_init(int8_t interface_id, net_tls_cipher_e cipher_mode, const uint8_t *key_material, uint32_t time_period_before_activate_key) { -#ifndef PANA +#ifndef PANA_SERVER (void)interface_id; (void)cipher_mode; (void)key_material; @@ -1092,7 +1092,7 @@ int8_t arm_pana_server_library_init(int8_t interface_id, net_tls_cipher_e cipher int8_t arm_pana_activate_new_key(int8_t interface_id) { -#ifndef PANA +#ifndef PANA_SERVER (void)interface_id; #endif return pana_server_trig_new_key(interface_id); @@ -1100,7 +1100,7 @@ int8_t arm_pana_activate_new_key(int8_t interface_id) int8_t arm_pana_server_key_update(int8_t interface_id, const uint8_t *network_key_material) { -#ifndef PANA +#ifndef PANA_SERVER (void)interface_id; (void)network_key_material; #endif @@ -1199,7 +1199,7 @@ int8_t arm_6lowpan_bootsrap_set_for_selected_interface(int8_t interface_id) int8_t arm_nwk_interface_configure_6lowpan_bootstrap_set(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode, net_6lowpan_mode_extension_e net_6lowpan_mode_extension) { int8_t ret_val; - + (void)bootstrap_mode; ret_val = arm_6lowpan_bootsrap_set_for_selected_interface(interface_id); if (ret_val == 0) {