diff --git a/features/nanostack/sal-stack-nanostack/mbed_lib.json b/features/nanostack/sal-stack-nanostack/mbed_lib.json index 1fddbd2cbac..ce65c8a038a 100644 --- a/features/nanostack/sal-stack-nanostack/mbed_lib.json +++ b/features/nanostack/sal-stack-nanostack/mbed_lib.json @@ -5,6 +5,10 @@ "configuration": { "help": "Build time configuration. Refer to Handbook for valid values. Default: full stack", "value": "nanostack_full" + }, + "trace_max_level": { + "help": "One of mbed-trace level defines: TRACE_LEVEL_DEBUG, TRACE_LEVEL_INFO, TRACE_LEVEL_WARN or TRACE_LEVEL_ERROR", + "value": null } }, "macros": ["NS_USE_EXTERNAL_MBED_TLS"], diff --git a/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h b/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h index 9c1e4a03cb2..741953b2dec 100644 --- a/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h +++ b/features/nanostack/sal-stack-nanostack/nanostack/ws_bbr_api.h @@ -334,6 +334,19 @@ int ws_bbr_pan_configuration_get(int8_t interface_id, uint16_t *pan_id); */ int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id); +/** + * Sets Wi-SUN BSI + * + * Sets Wi-SUN PAN BSI. + * + * \param interface_id Network interface ID. + * \param new_bsi Identifier. + * + * \return 0, PAN BSI set. + * \return <0 PAN BSI set failed. + */ +int ws_bbr_bsi_set(int8_t interface_id, uint16_t new_bsi); + /** * Sets memory used for key storages * diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c index 83560e9298f..d2b306d465f 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c @@ -20,6 +20,8 @@ #include "ns_types.h" #include "ns_trace.h" #include "nsdynmemLIB.h" +#include "randLIB.h" +#include "common_functions.h" #include "net_interface.h" #include "socket_api.h" #include "eventOS_event.h" @@ -31,6 +33,7 @@ #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_pae_key_storage.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "RPL/rpl_control.h" #include "RPL/rpl_data.h" #include "Common_Protocols/icmpv6.h" @@ -61,6 +64,20 @@ static uint8_t current_instance_id = RPL_INSTANCE_ID; #define BBR_CHECK_INTERVAL 60 #define BBR_BACKUP_ULA_DELAY 300 +//TAG ID This must be update if NVM_BBR_INFO_LEN or data structure +#define NVM_BBR_INFO_TAG 1 +// BSI 2 bytes +#define NVM_BBR_INFO_LEN 2 + +typedef struct bbr_info_nvm_tlv { + uint16_t tag; /**< Unique tag */ + uint16_t len; /**< Number of the bytes after the length field */ + uint8_t data[NVM_BBR_INFO_LEN]; /**< Data */ +} bbr_info_nvm_tlv_t; + +//NVM file name +static const char *BBR_INFO_FILE = "pae_bbr_info"; + /* when creating BBR make ULA dodag ID always and when network becomes available add prefix to DHCP * * @@ -105,6 +122,52 @@ typedef struct dns_resolution { #define MAX_DNS_RESOLUTIONS 4 static dns_resolution_t pre_resolved_dns_queries[MAX_DNS_RESOLUTIONS] = {0}; +//BBR NVM info buffer + +#define BBR_NVM_BSI_OFFSET 0 +static bbr_info_nvm_tlv_t bbr_info_nvm_tlv = { + .tag = NVM_BBR_INFO_TAG, + .len = 0, + .data = {0} +}; + +static uint16_t ws_bbr_fhss_bsi = 0; + +static int8_t ws_bbr_nvm_info_read(bbr_info_nvm_tlv_t *tlv_entry) +{ + tlv_entry->tag = NVM_BBR_INFO_TAG; + tlv_entry->len = NVM_BBR_INFO_LEN; + + int8_t ret_val = ws_pae_nvm_store_tlv_file_read(BBR_INFO_FILE, (nvm_tlv_t *) &bbr_info_nvm_tlv); + + if (ret_val < 0 || tlv_entry->tag != NVM_BBR_INFO_TAG || tlv_entry->len != NVM_BBR_INFO_LEN) { + ws_pae_nvm_store_tlv_file_remove(BBR_INFO_FILE); + tlv_entry->len = 0; + return -1; + } + return 0; +} + +static void ws_bbr_nvm_info_write(bbr_info_nvm_tlv_t *tlv_entry) +{ + tlv_entry->tag = NVM_BBR_INFO_TAG; + tlv_entry->len = NVM_BBR_INFO_LEN; + ws_pae_nvm_store_tlv_file_write(BBR_INFO_FILE, (nvm_tlv_t *) tlv_entry); + tr_debug("BBR info NVM update"); +} + +static uint16_t ws_bbr_bsi_read(bbr_info_nvm_tlv_t *tlv_entry) +{ + if (tlv_entry->tag != NVM_BBR_INFO_TAG || tlv_entry->len != NVM_BBR_INFO_LEN) { + return 0; + } + return common_read_16_bit(tlv_entry->data + BBR_NVM_BSI_OFFSET); +} + +static void ws_bbr_bsi_write(bbr_info_nvm_tlv_t *tlv_entry, uint16_t bsi) +{ + common_write_16_bit(bsi, tlv_entry->data + BBR_NVM_BSI_OFFSET); +} static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, uint8_t version) { @@ -134,7 +197,6 @@ 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) { if (imin == 0 || doubling == 0) { @@ -785,6 +847,35 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur) return true; } + +void ws_bbr_init(protocol_interface_info_entry_t *interface) +{ + (void) interface; + //Read From NVM + if (ws_bbr_nvm_info_read(&bbr_info_nvm_tlv) < 0) { + //NVM value not available Randomize Value Here by first time + ws_bbr_fhss_bsi = randLIB_get_16bit(); + tr_debug("Randomized init value BSI %u", ws_bbr_fhss_bsi); + } else { + ws_bbr_fhss_bsi = ws_bbr_bsi_read(&bbr_info_nvm_tlv); + tr_debug("Read BSI %u from NVM", ws_bbr_fhss_bsi); + } +} + + +uint16_t ws_bbr_bsi_generate(protocol_interface_info_entry_t *interface) +{ + (void) interface; + //Give current one + uint16_t bsi = ws_bbr_fhss_bsi; + //Update value for next round + ws_bbr_fhss_bsi++; + //Store To NVN + ws_bbr_bsi_write(&bbr_info_nvm_tlv, ws_bbr_fhss_bsi); + ws_bbr_nvm_info_write(&bbr_info_nvm_tlv); + return bsi; +} + #endif //HAVE_WS_BORDER_ROUTER /* Public APIs @@ -1070,6 +1161,33 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min #endif } +int ws_bbr_bsi_set(int8_t interface_id, uint16_t new_bsi) +{ + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + + //Check if new value is different than current active + if (cur && cur->ws_info && cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + if (cur->ws_info->hopping_schdule.fhss_bsi == new_bsi) { + return 0; + } + tr_debug("New BSI %u to delayed activate", new_bsi); + ws_bootstrap_restart_delayed(cur->id); + } + + ws_bbr_bsi_write(&bbr_info_nvm_tlv, new_bsi); + ws_bbr_nvm_info_write(&bbr_info_nvm_tlv); + ws_bbr_fhss_bsi = new_bsi; + return 0; +#else + (void) new_bsi; + return -1; +#endif +} + + int ws_bbr_pan_configuration_set(int8_t interface_id, uint16_t pan_id) { (void) interface_id; diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h index 4c24191cb89..78892b9f1da 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -37,6 +37,9 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); bool ws_bbr_backbone_address_get(uint8_t *address); +uint16_t ws_bbr_bsi_generate(protocol_interface_info_entry_t *interface); +void ws_bbr_init(protocol_interface_info_entry_t *interface); + #else #define ws_bbr_seconds_timer( cur, seconds) @@ -46,6 +49,8 @@ bool ws_bbr_backbone_address_get(uint8_t *address); #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 +#define ws_bbr_bsi_generate(interface) 0 +#define ws_bbr_init(interface) (void) 0 #endif //HAVE_WS_BORDER_ROUTER diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c index f9020634b52..825c924b1fe 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c @@ -670,6 +670,9 @@ static int8_t ws_fhss_border_router_configure(protocol_interface_info_entry_t *c if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) { memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); } + + //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); ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); @@ -988,7 +991,10 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) tr_error("fhss initialization failed"); return -3; } - + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //BBR init like NVM read + ws_bbr_init(cur); + } // Save FHSS api cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); @@ -996,7 +1002,6 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) addr_interface_set_ll64(cur, NULL); cur->nwk_nd_re_scan_count = 0; - //WS_interface_up(cur); // Trigger discovery for bootstrap ret_val = nwk_6lowpan_up(cur); if (ret_val) { @@ -1487,12 +1492,6 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf ws_bootsrap_create_ll_address(ll_address, neighbor_info.neighbor->mac64); if (rpl_control_is_dodag_parent(cur, ll_address)) { - // automatic network size adjustment learned - if (cur->ws_info->cfg->gen.network_size == NETWORK_SIZE_AUTOMATIC && - cur->ws_info->pan_information.pan_size != pan_information.pan_size) { - ws_cfg_network_size_configure(cur, pan_information.pan_size); - } - cur->ws_info->pan_information.pan_size = pan_information.pan_size; cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; @@ -1584,6 +1583,27 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry llc_neighbour_req_t neighbor_info; bool neighbour_pointer_valid; + //Validate BSI + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + + if (cur->ws_info->ws_bsi_block.block_time && cur->ws_info->ws_bsi_block.old_bsi == ws_bs_ie.broadcast_schedule_identifier) { + tr_debug("Do not accept a old BSI: %u in time %"PRIu32, cur->ws_info->ws_bsi_block.old_bsi, cur->ws_info->ws_bsi_block.block_time); + //Refresh Block time when hear a old BSI + cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; + return; + } + + //When Config is learned and USE Parent BS is enabled compare is this new BSI + if (cur->ws_info->configuration_learned && cur->ws_info->pan_information.use_parent_bs && ws_bs_ie.broadcast_schedule_identifier != cur->ws_info->hopping_schdule.fhss_bsi) { + tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier); + cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; + cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi; + ws_bootstrap_event_discovery_start(cur); + return; + } + } + + if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { //If we are border router or learned configuration we only update already learned neighbours. neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false); @@ -2491,6 +2511,13 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); // Network key is valid, indicate border router IID to controller ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]); + //Update here Suplikant target by validated Primary Parent + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); + if (mac_neighbor) { + ws_pae_controller_set_target(cur, cur->ws_info->network_pan_id, mac_neighbor->mac64); + } + } // After successful DAO ACK connection to border router is verified cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; @@ -3657,6 +3684,16 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s } } + if (cur->ws_info->ws_bsi_block.block_time) { + if (cur->ws_info->ws_bsi_block.block_time > seconds) { + cur->ws_info->ws_bsi_block.block_time -= seconds; + } else { + //Clear A BSI blokker + cur->ws_info->ws_bsi_block.block_time = 0; + cur->ws_info->ws_bsi_block.old_bsi = 0; + } + } + ws_llc_timer_seconds(cur, seconds); } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c index 3c536fe254b..8366204e52a 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.c @@ -53,6 +53,7 @@ typedef struct ws_cfg_nw_size_s { ws_timing_cfg_t timing; /**< Timing configuration */ ws_bbr_cfg_t bbr; /**< RPL configuration */ ws_sec_prot_cfg_t sec_prot; /**< Security protocols configuration */ + ws_mpl_cfg_t mpl; /**< Multicast timing configuration*/ } ws_cfg_nw_size_t; static uint32_t ws_test_temporary_entry_lifetime = 0; @@ -136,6 +137,8 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate *cfg = (ws_cfgs_t *) &nw_size_external_cfg->bbr; } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.sec_prot) { *cfg = (ws_cfgs_t *) &nw_size_external_cfg->sec_prot; + } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.mpl) { + *cfg = (ws_cfgs_t *) &nw_size_external_cfg->mpl; } else { *cfg = ws_cfg_ptr; } @@ -251,6 +254,7 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ ws_cfg_timing_get(&nw_size_cfg.timing, NULL); ws_cfg_bbr_get(&nw_size_cfg.bbr, NULL); ws_cfg_sec_prot_get(&nw_size_cfg.sec_prot, NULL); + ws_cfg_mpl_get(&nw_size_cfg.mpl, NULL); ws_cfg_network_size_config_set_size set_function = NULL; @@ -300,12 +304,15 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ old_network_size == NETWORK_SIZE_AUTOMATIC) { ws_cfg_sec_prot_set(cur, &ws_cfg.sec_prot, &nw_size_cfg.sec_prot, &set_flags); } + if (ws_cfg_mpl_validate(&ws_cfg.mpl, &nw_size_cfg.mpl) == CFG_SETTINGS_CHANGED || + old_network_size == NETWORK_SIZE_AUTOMATIC) { + ws_cfg_mpl_set(cur, &ws_cfg.mpl, &nw_size_cfg.mpl, &set_flags); + } // If is in an automatic network size mode, updates automatic configuration 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; } @@ -319,6 +326,7 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 ws_cfg_timing_get(&new_nw_size_cfg.timing, &flags); ws_cfg_bbr_get(&new_nw_size_cfg.bbr, &flags); ws_cfg_sec_prot_get(&new_nw_size_cfg.sec_prot, &flags); + ws_cfg_mpl_get(&new_nw_size_cfg.mpl, &flags); if (!nw_size_external_cfg) { nw_size_external_cfg = ns_dyn_mem_alloc(sizeof(ws_cfg_nw_size_t)); @@ -347,10 +355,12 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 ws_cfg_timing_set(cur, NULL, &new_nw_size_cfg.timing, &flags); ws_cfg_bbr_set(cur, NULL, &new_nw_size_cfg.bbr, &flags); ws_cfg_sec_prot_set(cur, NULL, &new_nw_size_cfg.sec_prot, &flags); + ws_cfg_mpl_set(cur, &ws_cfg.mpl, &new_nw_size_cfg.mpl, &flags); return CFG_SETTINGS_OK; } + static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg) { // Configure the Wi-SUN parent configuration @@ -385,6 +395,14 @@ static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg) 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; cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + + // Multicast timing configuration + cfg->mpl.mpl_trickle_imin = MPL_SMALL_IMIN; + cfg->mpl.mpl_trickle_imax = MPL_SMALL_IMAX; + cfg->mpl.mpl_trickle_k = MPL_SMALL_K; + cfg->mpl.mpl_trickle_timer_exp = MPL_SMALL_EXPIRATIONS; + cfg->mpl.seed_set_entry_lifetime = MPL_SMALL_SEED_LIFETIME; + } static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg) @@ -421,6 +439,13 @@ static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg) 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; cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + + // Multicast timing configuration + cfg->mpl.mpl_trickle_imin = MPL_MEDIUM_IMIN; + cfg->mpl.mpl_trickle_imax = MPL_MEDIUM_IMAX; + cfg->mpl.mpl_trickle_k = MPL_MEDIUM_K; + cfg->mpl.mpl_trickle_timer_exp = MPL_MEDIUM_EXPIRATIONS; + cfg->mpl.seed_set_entry_lifetime = MPL_MEDIUM_SEED_LIFETIME; } static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) @@ -457,6 +482,14 @@ static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) 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; cfg->sec_prot.initial_key_retry_cnt = LARGE_NW_INITIAL_KEY_RETRY_COUNT; + + // Multicast timing configuration + cfg->mpl.mpl_trickle_imin = MPL_LARGE_IMIN; + cfg->mpl.mpl_trickle_imax = MPL_LARGE_IMAX; + cfg->mpl.mpl_trickle_k = MPL_LARGE_K; + cfg->mpl.mpl_trickle_timer_exp = MPL_LARGE_EXPIRATIONS; + cfg->mpl.seed_set_entry_lifetime = MPL_LARGE_SEED_LIFETIME; + } static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) @@ -493,6 +526,13 @@ static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) 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; cfg->sec_prot.initial_key_retry_cnt = EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT; + + // Multicast timing configuration + cfg->mpl.mpl_trickle_imin = MPL_XLARGE_IMIN; + cfg->mpl.mpl_trickle_imax = MPL_XLARGE_IMAX; + cfg->mpl.mpl_trickle_k = MPL_XLARGE_K; + cfg->mpl.mpl_trickle_timer_exp = MPL_XLARGE_EXPIRATIONS; + cfg->mpl.seed_set_entry_lifetime = MPL_XLARGE_SEED_LIFETIME; } static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) @@ -529,6 +569,13 @@ static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) 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; cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + + // Multicast timing configuration for certification uses the LARGE values as it is the one mentioned ins specification + cfg->mpl.mpl_trickle_imin = MPL_XLARGE_IMIN; + cfg->mpl.mpl_trickle_imax = MPL_XLARGE_IMAX; + cfg->mpl.mpl_trickle_k = MPL_XLARGE_K; + cfg->mpl.mpl_trickle_timer_exp = MPL_XLARGE_EXPIRATIONS; + cfg->mpl.seed_set_entry_lifetime = MPL_XLARGE_SEED_LIFETIME; } static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg) @@ -832,11 +879,11 @@ int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, w static int8_t ws_cfg_mpl_default_set(ws_mpl_cfg_t *cfg) { // MPL configuration - cfg->mpl_trickle_imin = DATA_MESSAGE_IMIN; - cfg->mpl_trickle_imax = DATA_MESSAGE_IMAX; - cfg->mpl_trickle_k = DATA_MESSAGE_K; - cfg->mpl_trickle_timer_exp = DATA_MESSAGE_TIMER_EXPIRATIONS; - cfg->seed_set_entry_lifetime = MPL_SEED_SET_ENTRY_TIMEOUT; + cfg->mpl_trickle_imin = MPL_MEDIUM_IMIN; + cfg->mpl_trickle_imax = MPL_MEDIUM_IMAX; + cfg->mpl_trickle_k = MPL_MEDIUM_K; + cfg->mpl_trickle_timer_exp = MPL_MEDIUM_EXPIRATIONS; + cfg->seed_set_entry_lifetime = MPL_MEDIUM_SEED_LIFETIME; return CFG_SETTINGS_OK; } @@ -869,6 +916,21 @@ int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg) int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg, uint8_t *flags) { uint8_t cfg_flags; + + // In Wi-SUN Border router will have modified settings to improve reliability + if (cur && cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + // Border router sends multiple packets to ensure start of sequence + if (new_cfg->mpl_trickle_timer_exp < MPL_BORDER_ROUTER_MIN_EXPIRATIONS) { + new_cfg->mpl_trickle_timer_exp = MPL_BORDER_ROUTER_MIN_EXPIRATIONS; + // Lifetime is calculated using the original IMAX + new_cfg->seed_set_entry_lifetime = new_cfg->mpl_trickle_imax * new_cfg->mpl_trickle_timer_exp * MPL_SAFE_HOP_COUNT; + } + // Border router should have shorter IMAX to speed startup + if (new_cfg->mpl_trickle_imax > MPL_BORDER_ROUTER_MAXIMUM_IMAX) { + new_cfg->mpl_trickle_imax = MPL_BORDER_ROUTER_MAXIMUM_IMAX; + } + } + int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_mpl_validate, (ws_cfgs_t *) &ws_cfg.mpl, &cfg_flags, flags); if (ret != CFG_SETTINGS_CHANGED) { return ret; @@ -1205,6 +1267,7 @@ int8_t ws_cfg_settings_get(protocol_interface_info_entry_t *cur, ws_cfg_t *cfg) ws_cfg_timing_get(&cfg->timing, NULL); ws_cfg_bbr_get(&cfg->bbr, NULL); ws_cfg_sec_prot_get(&cfg->sec_prot, NULL); + ws_cfg_mpl_get(&cfg->mpl, NULL); return CFG_SETTINGS_OK; } diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h index 48592b899a5..35490e33269 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_cfg_settings.h @@ -56,12 +56,12 @@ typedef struct ws_timing_cfg_s { * \brief Struct ws_rpl_cfg_t RPL configuration */ typedef struct ws_bbr_cfg_s { - uint8_t dio_interval_min; /**> DIO interval min; DEFAULT_DIO_INTERVAL_MIN; 2^value in milliseconds; range 1-255; default */ - uint8_t dio_interval_doublings; /**> DIO interval doublings; DEFAULT_DIO_INTERVAL_DOUBLINGS; range 1-8; default */ - uint8_t dio_redundancy_constant; /**> DIO redundancy constant; DEFAULT_DIO_REDUNDANCY_CONSTANT; range 0-10; default */ + uint8_t dio_interval_min; /**< DIO interval min; DEFAULT_DIO_INTERVAL_MIN; 2^value in milliseconds; range 1-255; default */ + uint8_t dio_interval_doublings; /**< DIO interval doublings; DEFAULT_DIO_INTERVAL_DOUBLINGS; range 1-8; default */ + uint8_t dio_redundancy_constant; /**< DIO redundancy constant; DEFAULT_DIO_REDUNDANCY_CONSTANT; range 0-10; default */ 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 dhcp_address_lifetime; /**< DHCP address lifetime in seconds minimum 2 hours and maximum as days hours*/ } ws_bbr_cfg_t; /** diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h index cb29ab6c35c..5b468d27adb 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h @@ -73,6 +73,11 @@ typedef struct { uint8_t index; } ws_pending_key_index_t; +typedef struct { + uint32_t block_time; + uint16_t old_bsi; +} ws_bsi_block_t; + typedef NS_LIST_HEAD(ws_nud_table_entry_t, link) ws_nud_table_list_t; typedef struct ws_info_s { @@ -89,6 +94,7 @@ typedef struct ws_info_s { parent_info_t parent_info[WS_PARENT_LIST_SIZE]; parent_info_list_t parent_list_free; parent_info_list_t parent_list_reserved; + 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 */ diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h index 899b25afcd0..6efcf20c802 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h @@ -130,14 +130,37 @@ extern uint8_t DEVICE_MIN_SENS; /* Multicast MPL data message parameters - * IMIN = 10 seconds, IMAX = 3 doublings */ - -#define DATA_MESSAGE_IMIN 10 -#define DATA_MESSAGE_TIMER_EXPIRATIONS 3 -#define DATA_MESSAGE_IMAX 80 -#define DATA_MESSAGE_K 8 -#define MPL_SEED_SET_ENTRY_TIMEOUT (DATA_MESSAGE_IMAX * 24 * 4) // 10 seconds per hop making this 240 seconds +#define MPL_SAFE_HOP_COUNT 6 + +/*Border router override to optimize the multicast startup*/ +#define MPL_BORDER_ROUTER_MIN_EXPIRATIONS 2 +#define MPL_BORDER_ROUTER_MAXIMUM_IMAX 40 + +/*Small network size*/ +#define MPL_SMALL_IMIN 1 +#define MPL_SMALL_IMAX 10 +#define MPL_SMALL_EXPIRATIONS 1 +#define MPL_SMALL_K 8 +#define MPL_SMALL_SEED_LIFETIME (MPL_SMALL_IMAX * MPL_SAFE_HOP_COUNT * (MPL_SMALL_EXPIRATIONS + 1)) // time that packet should get to safe distance +/*Medium network size*/ +#define MPL_MEDIUM_IMIN 5 +#define MPL_MEDIUM_IMAX 20 +#define MPL_MEDIUM_EXPIRATIONS 2 +#define MPL_MEDIUM_K 8 +#define MPL_MEDIUM_SEED_LIFETIME (MPL_MEDIUM_IMAX * MPL_SAFE_HOP_COUNT * (MPL_MEDIUM_EXPIRATIONS + 1)) // time that packet should get to safe distance +/*Large network size*/ +#define MPL_LARGE_IMIN 5 +#define MPL_LARGE_IMAX 40 +#define MPL_LARGE_EXPIRATIONS 2 +#define MPL_LARGE_K 8 +#define MPL_LARGE_SEED_LIFETIME (MPL_LARGE_IMAX * MPL_SAFE_HOP_COUNT * (MPL_LARGE_EXPIRATIONS + 1)) // time that packet should get to safe distance +/*xtra large network size*/ +#define MPL_XLARGE_IMIN 10 +#define MPL_XLARGE_IMAX 80 +#define MPL_XLARGE_EXPIRATIONS 2 +#define MPL_XLARGE_K 8 +#define MPL_XLARGE_SEED_LIFETIME (MPL_XLARGE_IMAX * MPL_SAFE_HOP_COUNT * (MPL_XLARGE_EXPIRATIONS + 1)) // time that packet should get to safe distance /* DHCP client timeout configuration values * diff --git a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c index 07d5c105b65..35647c1e121 100644 --- a/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c @@ -102,6 +102,10 @@ static int own_ceil(float value) static void ws_neighbor_calculate_ufsi_drift(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp, uint8_t address[8]) { if (ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp && ws_neighbor->fhss_data.uc_timing_info.ufsi) { + // No UFSI on fixed channel + if (ws_neighbor->fhss_data.uc_timing_info.unicast_channel_function == WS_FIXED_CHANNEL) { + return; + } uint32_t seq_length = 0x10000; if (ws_neighbor->fhss_data.uc_timing_info.unicast_channel_function == WS_TR51CF) { seq_length = ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels; diff --git a/features/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h b/features/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h index c4e6e638c27..23ec4db7eca 100644 --- a/features/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h +++ b/features/nanostack/sal-stack-nanostack/source/Core/include/ns_socket.h @@ -130,7 +130,7 @@ typedef struct socket { int8_t id; /*!< socket id */ uint8_t flags; /*!< Socket option flags */ int8_t tasklet; /*!< Receiver tasklet */ - uint8_t refcount; + uint16_t refcount; socket_family_t family; socket_type_t type; int8_t default_interface_id; diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c index e97416c752f..72ddf1281f6 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.c @@ -115,6 +115,8 @@ static void rpl_downward_topo_sort_invalidate(rpl_instance_t *instance); /* The PCS mask */ #define PCSMASK(pcs) ((uint8_t)(0x100 - PCBIT(pcs))) +static bool rpl_instance_push_address_registration(protocol_interface_info_entry_t *interface, rpl_neighbour_t *neighbour, if_address_entry_t *addr); +static if_address_entry_t *rpl_interface_addr_get(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); /* * 0 1 2 3 4 5 6 7 @@ -178,7 +180,7 @@ static void rpl_downward_target_refresh(rpl_dao_target_t *target) target->info.non_root.path_lifetime = 0; } -static bool rpl_instance_parent_selection_ready(rpl_instance_t *instance) +bool rpl_instance_parent_selection_ready(rpl_instance_t *instance) { rpl_neighbour_t *neighbour = ns_list_get_first(&instance->candidate_neighbours); if (neighbour && neighbour->dodag_parent && neighbour->dao_path_control) { @@ -723,7 +725,11 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) instance->dao_in_transit = false; instance->dao_attempt = 0; instance->dao_retry_timer = 0; - instance->delay_dao_timer = 0; + // Primary parent deletion will trigger parent selection + // While waiting, leave dao_timer "running" to indicate DAO incomplete + // This is checked in rpl_upward_dio_timer to delay initial DIO sending + // If we stopped the timer, that code might think DAO registration was complete + instance->delay_dao_timer = 0xffff; return; } @@ -1537,6 +1543,25 @@ bool rpl_instance_dao_received(rpl_instance_t *instance, const uint8_t src[16], } #endif // HAVE_RPL_DAO_HANDLING +static uint16_t rpl_instance_address_registration_start(rpl_instance_t *instance, rpl_dao_target_t *pending_target) +{ + rpl_neighbour_t *pref_parent = rpl_instance_preferred_parent(instance); + protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_rpl_domain(instance->domain, -1); + if (!interface || !pref_parent) { + return 1; + } + if_address_entry_t *address = rpl_interface_addr_get(interface, pending_target->prefix); + if (!address) { + return 1; + } + if (!rpl_instance_push_address_registration(interface, pref_parent, address)) { + return 1; + } + tr_debug("Extra Address Confirmation trig...next dao trig 10s"); + return 100; + +} + void rpl_instance_dao_acked(rpl_instance_t *instance, const uint8_t src[16], int8_t interface_id, uint8_t dao_sequence, uint8_t status) { if (!instance->dao_in_transit || dao_sequence != instance->dao_sequence_in_transit) { @@ -1568,6 +1593,7 @@ void rpl_instance_dao_acked(rpl_instance_t *instance, const uint8_t src[16], int } bool more_to_do = false; + rpl_dao_target_t *pending_target = NULL; ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) { if (target->root) { continue; @@ -1585,12 +1611,14 @@ void rpl_instance_dao_acked(rpl_instance_t *instance, const uint8_t src[16], int target->info.non_root.pc_assigned |= target->info.non_root.pc_assigning; } else { target->info.non_root.pc_to_retry |= target->info.non_root.pc_assigning; + } target->info.non_root.pc_assigning = 0; } target->info.non_root.pc_assigned &= target->path_control; if (target->info.non_root.pc_assigned != target->path_control) { more_to_do = true; + pending_target = target; } else { if (target->published && target->info.non_root.refresh_timer == 0) { uint32_t t; @@ -1612,7 +1640,14 @@ void rpl_instance_dao_acked(rpl_instance_t *instance, const uint8_t src[16], int } if (more_to_do) { - rpl_instance_dao_trigger(instance, 1); + uint16_t dao_trig_time = 1; + if (pending_target && rpl_policy_parent_confirmation_requested()) { + //Possible NS ARO trig + dao_trig_time = rpl_instance_address_registration_start(instance, pending_target); + } + + rpl_instance_dao_trigger(instance, dao_trig_time); + } else { rpl_control_event(instance->domain, RPL_EVENT_DAO_DONE); } @@ -1863,9 +1898,6 @@ static void rpl_instance_address_registration_cancel(rpl_instance_t *instance) instance->wait_response = NULL; instance->pending_neighbour_confirmation = false; - instance->delay_dao_timer = 0; - instance->dao_in_transit = false; - instance->dao_retry_timer = 0; } static void rpl_instance_address_registration_retry(rpl_dao_target_t *dao_target) @@ -1881,6 +1913,11 @@ void rpl_instance_parent_address_reg_timer_update(rpl_instance_t *instance, uint return; //No need validate any confirmation } + if (rpl_instance_am_root(instance)) { + rpl_instance_address_registration_cancel(instance); + return; + } + //Verify that we have selected parent and it have a dao path control if (!rpl_instance_parent_selection_ready(instance)) { rpl_instance_address_registration_cancel(instance); diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.h b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.h index c7cd66f27f1..73cceeb856c 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.h +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_downward.h @@ -46,6 +46,7 @@ void rpl_instance_parent_address_reg_timer_update(struct rpl_instance *instance, void rpl_instance_send_address_registration(rpl_instance_t *instance, const uint8_t addr[16]); bool rpl_instance_address_registration_done(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, rpl_neighbour_t *neighbour, uint8_t status); struct rpl_dao_target *rpl_instance_get_active_target_confirmation(struct rpl_instance *instance); +bool rpl_instance_parent_selection_ready(struct rpl_instance *instance); #ifdef HAVE_RPL_DAO_HANDLING bool rpl_instance_dao_received(struct rpl_instance *instance, const uint8_t src[16], int8_t interface_id, bool multicast, const uint8_t *opts, uint16_t opts_len, uint8_t *status_out); diff --git a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c index babb5d0716d..dec173ef71d 100644 --- a/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c +++ b/features/nanostack/sal-stack-nanostack/source/RPL/rpl_upward.c @@ -1836,11 +1836,12 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) { return; } + /* Delay sending first DIO if we are still potentially gathering info */ /* Important to always send DIOs if we ever have sent any, so we can indicate problems to others */ - if (!instance->last_advertised_dodag_version && rpl_policy_parent_confirmation_requested()) { - // We dont have any valid address in interface - if (ns_list_count(&instance->dao_targets) == 0) { + if (!rpl_instance_am_root(instance) && !instance->last_advertised_dodag_version && rpl_policy_parent_confirmation_requested()) { + // We dont have any valid parent selected + if (!rpl_instance_parent_selection_ready(instance)) { return; } /* Address registrations for parent ongoing*/ @@ -1852,6 +1853,7 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) return; } } + if (trickle_timer(&instance->dio_timer, &dodag->dio_timer_params, ticks)) { instance->dio_not_consistent = false; rpl_instance_dio_trigger(instance, NULL, NULL); diff --git a/features/nanostack/sal-stack-nanostack/source/nsconfig.h b/features/nanostack/sal-stack-nanostack/source/nsconfig.h index dff8a5622d4..dfb182a5aff 100644 --- a/features/nanostack/sal-stack-nanostack/source/nsconfig.h +++ b/features/nanostack/sal-stack-nanostack/source/nsconfig.h @@ -54,6 +54,13 @@ #endif #endif /* HAVE_WS */ +/* Configure trace level for Nanostack */ +#ifdef MBED_CONF_NANOSTACK_TRACE_MAX_LEVEL +#ifdef MBED_TRACE_MAX_LEVEL +#undef MBED_TRACE_MAX_LEVEL +#endif /* MBED_TRACE_MAX_LEVEL */ +#define MBED_TRACE_MAX_LEVEL MBED_CONF_NANOSTACK_TRACE_MAX_LEVEL +#endif /* MBED_CONF_NANOSTACK_TRACE_MAX_LEVEL */ #endif // ifndef _NANOSTACK_SOURCE_CONFIG_H