Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ws_bootstrap.c Source File

ws_bootstrap.c

00001 /*
00002  * Copyright (c) 2018-2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include <string.h>
00019 #include "nsconfig.h"
00020 #include "ns_types.h"
00021 #include "ns_trace.h"
00022 #include "net_interface.h"
00023 #include "eventOS_event.h"
00024 #include "randLIB.h"
00025 #include "common_functions.h"
00026 #include "mac_common_defines.h"
00027 #include "sw_mac.h"
00028 #include "ccmLIB.h"
00029 #include "NWK_INTERFACE/Include/protocol.h"
00030 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
00031 #include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h"
00032 #include "ipv6_stack/protocol_ipv6.h"
00033 #include "6LoWPAN/MAC/mac_helper.h"
00034 #include "6LoWPAN/MAC/mac_data_poll.h"
00035 #include "6LoWPAN/MAC/mpx_api.h"
00036 #include "6LoWPAN/MAC/mac_ie_lib.h"
00037 #include "MPL/mpl.h"
00038 #include "RPL/rpl_protocol.h"
00039 #include "RPL/rpl_control.h"
00040 #include "RPL/rpl_data.h"
00041 #include "Common_Protocols/icmpv6.h"
00042 #include "Common_Protocols/icmpv6_radv.h"
00043 #include "Common_Protocols/ipv6_constants.h"
00044 #include "Service_Libs/Trickle/trickle.h"
00045 #include "Service_Libs/fhss/channel_list.h"
00046 #include "6LoWPAN/ws/ws_common_defines.h"
00047 #include "6LoWPAN/ws/ws_common_defines.h"
00048 #include "6LoWPAN/ws/ws_config.h"
00049 #include "6LoWPAN/ws/ws_common.h"
00050 #include "6LoWPAN/ws/ws_bootstrap.h"
00051 #include "6LoWPAN/ws/ws_bbr_api_internal.h"
00052 #include "6LoWPAN/ws/ws_common_defines.h"
00053 #include "6LoWPAN/ws/ws_llc.h"
00054 #include "6LoWPAN/ws/ws_neighbor_class.h"
00055 #include "6LoWPAN/ws/ws_ie_lib.h"
00056 #include "6LoWPAN/ws/ws_stats.h"
00057 #include "6LoWPAN/lowpan_adaptation_interface.h"
00058 #include "Service_Libs/etx/etx.h"
00059 #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
00060 #include "Service_Libs/nd_proxy/nd_proxy.h"
00061 #include "Service_Libs/blacklist/blacklist.h"
00062 #include "platform/topo_trace.h"
00063 #include "libDHCPv6/libDHCPv6.h"
00064 #include "DHCPv6_client/dhcpv6_client_api.h"
00065 #include "ws_management_api.h"
00066 #include "net_rpl.h"
00067 #include "mac_api.h"
00068 #include "6LoWPAN/ws/ws_pae_controller.h"
00069 #include "6LoWPAN/ws/ws_eapol_pdu.h"
00070 #include "6LoWPAN/ws/ws_eapol_auth_relay.h"
00071 #include "6LoWPAN/ws/ws_eapol_relay.h"
00072 
00073 #define TRACE_GROUP "wsbs"
00074 
00075 #ifdef HAVE_WS
00076 
00077 static void ws_bootstrap_event_handler(arm_event_s *event);
00078 static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state);
00079 static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur);
00080 static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur);
00081 static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur);
00082 static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data);
00083 
00084 static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new);
00085 static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur);
00086 static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur);
00087 static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur);
00088 
00089 static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur);
00090 static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t operation, uint8_t index, uint8_t *key);
00091 static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot);
00092 static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index);
00093 static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot);
00094 static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot);
00095 static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64);
00096 static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur);
00097 static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
00098 static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
00099 static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data);
00100 static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface);
00101 
00102 
00103 static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur);
00104 static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create);
00105 
00106 typedef enum {
00107     WS_PARENT_SOFT_SYNCH = 0,  /**< let FHSS make decision if synchronization is needed*/
00108     WS_PARENT_HARD_SYNCH,      /**< Synch FHSS with latest synch information*/
00109     WS_EAPOL_PARENT_SYNCH,  /**< Broadcast synch with EAPOL parent*/
00110 } ws_parent_synch_e;
00111 
00112 
00113 static void ws_bootsrap_create_ll_address(uint8_t *ll_address, const uint8_t *mac64)
00114 {
00115     memcpy(ll_address, ADDR_LINK_LOCAL_PREFIX, 8);
00116     memcpy(ll_address + 8, mac64, 8);
00117     ll_address[8] ^= 2;
00118 }
00119 
00120 mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64)
00121 
00122 {
00123     mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT);
00124     if (neighbor) {
00125         return neighbor;
00126     }
00127 
00128     neighbor = mac_neighbor_table_entry_allocate(mac_neighbor_info(interface), src64);
00129     if (!neighbor) {
00130         return NULL;
00131     }
00132     // TODO only call these for new neighbour
00133     mlme_device_descriptor_t device_desc;
00134     neighbor->lifetime  = WS_NEIGHBOR_LINK_TIMEOUT;
00135     neighbor->link_lifetime  = WS_NEIGHBOR_LINK_TIMEOUT;
00136     tr_debug("Added new neighbor %s : index:%u", trace_array(src64, 8), neighbor->index );
00137     mac_helper_device_description_write(interface, &device_desc, neighbor->mac64 , neighbor->mac16 , 0, false);
00138     mac_helper_devicetable_set(&device_desc, interface, neighbor->index , interface->mac_parameters->mac_default_key_index, true);
00139     return neighbor;
00140 }
00141 
00142 static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, mac_neighbor_table_entry_t *entry_ptr)
00143 {
00144     mac_helper_devicetable_remove(interface->mac_api, entry_ptr->index , entry_ptr->mac64 );
00145     etx_neighbor_remove(interface->id, entry_ptr->index );
00146     ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, entry_ptr->index );
00147 }
00148 
00149 static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface)
00150 {
00151 
00152     mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface));
00153 }
00154 
00155 static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_entry *interface, const struct if_address_entry *addr, if_address_callback_t reason)
00156 {
00157     /* No need for LL address registration */
00158     if (addr->source == ADDR_SOURCE_UNKNOWN) {
00159         return;
00160     }
00161     if (reason == ADDR_CALLBACK_DAD_COMPLETE) {
00162         //Trig Address Registartion only when Bootstrap is ready
00163         if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE && addr->source != ADDR_SOURCE_DHCP) {
00164             tr_debug("Address registration %s", trace_ipv6(addr->address));
00165             rpl_control_register_address(interface, addr->address);
00166         }
00167         if (addr_ipv6_scope(addr->address, interface) > IPV6_SCOPE_LINK_LOCAL) {
00168             // at least ula address available inside mesh.
00169             interface->global_address_available = true;
00170         }
00171 
00172     } else if (reason == ADDR_CALLBACK_DELETED) {
00173         // What to do?
00174         // Go through address list and check if there is global address still available
00175         if (addr->source == ADDR_SOURCE_DHCP) {
00176             //Deprecate dhcpv address
00177             uint8_t address[16];
00178             memcpy(address, addr->address, 16);
00179             dhcp_client_global_address_delete(interface->id, NULL, address);
00180         }
00181         //Discover prefix policy
00182         addr_policy_remove_by_label(WS_NON_PREFFRED_LABEL);
00183 
00184         interface->global_address_available = false;
00185         ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) {
00186             if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) {
00187                 // at least ula address available inside mesh.
00188                 interface->global_address_available = true;
00189                 break;
00190             }
00191         }
00192     } else if (reason == ADDR_CALLBACK_TIMER) {
00193         if (addr->source != ADDR_SOURCE_DHCP) {
00194             tr_debug("Address Re registration %s", trace_ipv6(addr->address));
00195             //Register
00196             rpl_control_register_address(interface, addr->address);
00197         }
00198     }
00199 }
00200 
00201 static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur)
00202 {
00203     if (cur->bootStrapId < 0) {
00204         cur->bootStrapId = eventOS_event_handler_create(&ws_bootstrap_event_handler, WS_INIT_EVENT);
00205         tr_debug("WS tasklet init");
00206     }
00207 
00208     if (cur->bootStrapId < 0) {
00209         tr_error("tasklet init failed");
00210         return -1;
00211     }
00212 
00213 
00214     return 0;
00215 }
00216 static void ws_nwk_event_post(protocol_interface_info_entry_t *cur, arm_nwk_interface_status_type_e posted_event)
00217 {
00218     arm_event_s event = {
00219         .receiver = cur->net_start_tasklet,
00220         .sender = protocol_read_tasklet_id(), /**< Event sender Tasklet ID */
00221         .event_type = ARM_LIB_NWK_INTERFACE_EVENT,
00222         .event_data = posted_event,
00223         .event_id = (int8_t) cur->id,
00224         .data_ptr = NULL,
00225         .priority = ARM_LIB_LOW_PRIORITY_EVENT,
00226     };
00227     if (eventOS_event_send(&event) != 0) {
00228         tr_error("nwk_net_event_post(): event send failed");
00229     }
00230 }
00231 
00232 static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data)
00233 {
00234     arm_event_s event = {
00235         .receiver = interface_id,
00236         .sender = 0,
00237         .event_type = event_type,
00238         .priority = priority,
00239         .data_ptr = event_data,
00240     };
00241     return eventOS_event_send(&event);
00242 }
00243 
00244 static void ws_nud_table_reset(protocol_interface_info_entry_t *cur)
00245 {
00246     //Empty active list
00247     ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) {
00248         ns_list_remove(&cur->ws_info->active_nud_process, entry);
00249     }
00250 
00251     //Empty free list
00252     ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->free_nud_entries) {
00253         ns_list_remove(&cur->ws_info->free_nud_entries, entry);
00254     }
00255     //Add to free list to full
00256     for (int i = 0; i < ACTIVE_NUD_PROCESS_MAX; i++) {
00257         ns_list_add_to_end(&cur->ws_info->free_nud_entries, &cur->ws_info->nud_table_entrys[i]);
00258     }
00259 }
00260 
00261 static ws_nud_table_entry_t *ws_nud_entry_get_free(protocol_interface_info_entry_t *cur)
00262 {
00263     ws_nud_table_entry_t *entry = ns_list_get_first(&cur->ws_info->free_nud_entries);
00264     if (entry) {
00265         entry->wait_response = false;
00266         entry->retry_count = 0;
00267         entry->nud_process = false;
00268         entry->timer = randLIB_get_random_in_range(1, 900);
00269         entry->neighbor_info = NULL;
00270         ns_list_remove(&cur->ws_info->free_nud_entries, entry);
00271         ns_list_add_to_end(&cur->ws_info->active_nud_process, entry);
00272     }
00273     return entry;
00274 }
00275 
00276 
00277 void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor)
00278 {
00279     ws_nud_table_entry_t *entry = ws_nud_entry_discover(cur, neighbor);
00280 
00281     if (entry) {
00282         mac_neighbor_table_entry_t *mac_neighbor = neighbor;
00283         ns_list_remove(&cur->ws_info->active_nud_process, entry);
00284         ns_list_add_to_end(&cur->ws_info->free_nud_entries, entry);
00285         if (mac_neighbor->nud_active ) {
00286             mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), mac_neighbor, mac_neighbor->link_lifetime );
00287         }
00288 
00289         mac_neighbor_table_neighbor_connected(mac_neighbor_info(cur), mac_neighbor);
00290     }
00291 }
00292 
00293 
00294 static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor)
00295 {
00296     ns_list_foreach(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) {
00297         if (entry->neighbor_info == neighbor) {
00298             return entry;
00299         }
00300     }
00301     return NULL;
00302 }
00303 
00304 
00305 static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_table_entry_t *entry)
00306 {
00307     mac_neighbor_table_entry_t *neighbor = entry->neighbor_info;
00308     ns_list_remove(&cur->ws_info->active_nud_process, entry);
00309     ns_list_add_to_end(&cur->ws_info->free_nud_entries, entry);
00310     if (neighbor->nud_active ) {
00311         neighbor->nud_active  = false;
00312         mac_neighbor_info(cur)->active_nud_process--;
00313     }
00314 }
00315 
00316 static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr)
00317 {
00318     ws_nud_table_entry_t *nud_entry = ws_nud_entry_discover(cur, entry_ptr);
00319     if (nud_entry) {
00320         ws_nud_state_clean(cur, nud_entry);
00321     }
00322 }
00323 
00324 static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor)
00325 {
00326     //Send NS
00327     uint8_t ll_target[16];
00328     ws_bootsrap_create_ll_address(ll_target, neighbor->mac64 );
00329     tr_info("NUD generate NS %u", neighbor->index );
00330     buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL);
00331     if (buffer) {
00332         protocol_push(buffer);
00333         return true;
00334     }
00335     return false;
00336 }
00337 
00338 void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks)
00339 {
00340     //Convert TICKS to real milliseconds
00341     if (ticks > 0xffff / 100) {
00342         ticks = 0xffff;
00343     } else if (ticks == 0) {
00344         ticks = 1;
00345     } else {
00346         ticks *= 100;
00347     }
00348 
00349     ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) {
00350         if (entry->timer <= ticks) {
00351             //TX Process or timeout
00352             if (entry->wait_response) {
00353                 //Timeout for NUD or Probe
00354                 if (entry->nud_process) {
00355                     tr_debug("NUD NA timeout");
00356                     if (entry->retry_count < 2) {
00357                         entry->timer = randLIB_get_random_in_range(1, 900);
00358                         entry->wait_response = false;
00359                     } else {
00360                         //Clear entry from active list
00361                         ws_nud_state_clean(cur, entry);
00362                         //Remove whole entry
00363                         mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), entry->neighbor_info);
00364                     }
00365                 } else {
00366                     ws_nud_state_clean(cur, entry);
00367                 }
00368 
00369             } else {
00370                 //Random TX wait period is over
00371                 entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info);
00372                 if (!entry->wait_response) {
00373                     if (entry->nud_process && entry->retry_count < 2) {
00374                         entry->timer = randLIB_get_random_in_range(1, 900);
00375                     } else {
00376                         //Clear entry from active list
00377                         //Remove and try again later on
00378                         ws_nud_state_clean(cur, entry);
00379                     }
00380                 } else {
00381                     entry->retry_count++;
00382                     entry->timer = 5001;
00383                 }
00384             }
00385         } else {
00386             entry->timer -= ticks;
00387         }
00388     }
00389 }
00390 
00391 static fhss_ws_neighbor_timing_info_t *ws_get_neighbor_info(const fhss_api_t *api, uint8_t eui64[8])
00392 {
00393     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_fhss_api(api);
00394     if (!cur || !cur->mac_parameters || !mac_neighbor_info(cur)) {
00395         return NULL;
00396     }
00397     mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), eui64, MAC_ADDR_MODE_64_BIT);
00398     if (!mac_neighbor) {
00399         return NULL;
00400     }
00401     ws_neighbor_class_entry_t *ws_neighbor =  ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_neighbor->index );
00402     if (!ws_neighbor) {
00403         return NULL;
00404     }
00405     return &ws_neighbor->fhss_data;
00406 }
00407 static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry *cur, const fhss_ws_configuration_t *fhss_configuration)
00408 {
00409     memcpy(cur->ws_info->hopping_schdule.channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8);
00410     cur->ws_info->hopping_schdule.uc_fixed_channel = fhss_configuration->unicast_fixed_channel;
00411     cur->ws_info->hopping_schdule.bc_fixed_channel = fhss_configuration->broadcast_fixed_channel;
00412     cur->ws_info->hopping_schdule.uc_channel_function = fhss_configuration->ws_uc_channel_function;
00413     cur->ws_info->hopping_schdule.bc_channel_function = fhss_configuration->ws_bc_channel_function;
00414     cur->ws_info->hopping_schdule.fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval;
00415     cur->ws_info->hopping_schdule.fhss_broadcast_interval = fhss_configuration->fhss_broadcast_interval;
00416     cur->ws_info->hopping_schdule.fhss_uc_dwell_interval = fhss_configuration->fhss_uc_dwell_interval;
00417     cur->ws_info->hopping_schdule.fhss_bsi = fhss_configuration->bsi;
00418 }
00419 
00420 static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
00421 {
00422     fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
00423 
00424     if (!fhss_api || (fhss_api && cur->ws_info->fhss_owner)) {
00425         // When FHSS doesn't exist yet, create one
00426         fhss_ws_configuration_t fhss_configuration;
00427         memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t));
00428         ws_generate_channel_list(fhss_configuration.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
00429 
00430         // using bitwise AND operation for user set channel mask to remove channels not allowed in this device
00431         for (uint8_t n = 0; n < 8; n++) {
00432             fhss_configuration.channel_mask[n] &= cur->ws_info->fhss_channel_mask[n];
00433         }
00434 
00435         fhss_configuration.fhss_uc_dwell_interval = cur->ws_info->fhss_uc_dwell_interval;
00436         fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_uc_channel_function;
00437         fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function;
00438         fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval;
00439         fhss_configuration.fhss_broadcast_interval = cur->ws_info->fhss_bc_interval;
00440 
00441         if (!fhss_api) {
00442             fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
00443             if (!fhss_api) {
00444                 tr_error("fhss create failed");
00445                 return -1;
00446             }
00447             ns_sw_mac_fhss_register(cur->mac_api, fhss_api);
00448             cur->ws_info->fhss_owner = true;
00449         } else {
00450             //Configuration set
00451             ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
00452 
00453             if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
00454                 ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0);
00455             } else {
00456                 //Clear OWN HOP
00457                 ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff);
00458             }
00459         }
00460     } else {
00461         // Read defaults from the configuration to help FHSS testing
00462         const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(fhss_api);
00463         if (!fhss_configuration) {
00464             // no configuration set yet
00465             return 0;
00466         }
00467         memcpy(cur->ws_info->fhss_channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8);
00468         cur->ws_info->fhss_uc_channel_function = fhss_configuration->ws_uc_channel_function;
00469         cur->ws_info->fhss_bc_channel_function = fhss_configuration->ws_bc_channel_function;
00470         cur->ws_info->fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval;
00471         cur->ws_info->fhss_bc_interval = fhss_configuration->fhss_broadcast_interval;
00472         cur->ws_info->fhss_uc_dwell_interval = fhss_configuration->fhss_uc_dwell_interval;
00473         cur->ws_info->fhss_bc_fixed_channel = fhss_configuration->broadcast_fixed_channel;
00474         cur->ws_info->fhss_uc_fixed_channel = fhss_configuration->unicast_fixed_channel;
00475     }
00476     return 0;
00477 }
00478 static int8_t ws_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration)
00479 {
00480     fhss_configuration->fhss_uc_dwell_interval = cur->ws_info->fhss_uc_dwell_interval;
00481     fhss_configuration->ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_uc_channel_function;
00482     fhss_configuration->ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function;
00483     fhss_configuration->fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval;
00484     fhss_configuration->fhss_broadcast_interval = cur->ws_info->fhss_bc_interval;
00485     if (cur->ws_info->fhss_uc_fixed_channel != 0xffff) {
00486         fhss_configuration->unicast_fixed_channel = cur->ws_info->fhss_uc_fixed_channel;
00487     }
00488     fhss_configuration->broadcast_fixed_channel = cur->ws_info->fhss_bc_fixed_channel;
00489     ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
00490 
00491     // using bitwise AND operation for user set channel mask to remove channels not allowed in this device
00492     for (uint8_t n = 0; n < 8; n++) {
00493         fhss_configuration->channel_mask[n] &= cur->ws_info->fhss_channel_mask[n];
00494     }
00495     return 0;
00496 }
00497 static int8_t ws_fhss_border_router_configure(protocol_interface_info_entry_t *cur)
00498 {
00499     // Read configuration of existing FHSS and start using the default values for any network
00500     fhss_ws_configuration_t fhss_configuration;
00501     memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t));
00502 
00503     if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) {
00504         memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t));
00505     }
00506     ws_fhss_set_defaults(cur, &fhss_configuration);
00507     ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
00508     ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
00509 
00510     return 0;
00511 }
00512 
00513 static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels)
00514 {
00515     if (configured_fixed_channel == 0xFFFF) {
00516         return randLIB_get_random_in_range(0, number_of_channels - 1);
00517     } else {
00518         return configured_fixed_channel;
00519     }
00520 }
00521 
00522 static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
00523 {
00524     // Read configuration of existing FHSS and start using the default values for any network
00525     fhss_ws_configuration_t fhss_configuration;
00526     memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t));
00527 
00528     if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) {
00529         memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t));
00530     }
00531 
00532     fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL;
00533     fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL;
00534     fhss_configuration.fhss_broadcast_interval = 0;
00535     uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
00536     uint8_t tmp_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
00537     fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel;
00538     fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel;
00539     ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
00540     ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff);
00541     ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
00542 
00543     return 0;
00544 }
00545 
00546 static int8_t ws_fhss_enable(protocol_interface_info_entry_t *cur)
00547 {
00548     const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(cur->ws_info->fhss_api);
00549 
00550     if (!cur->ws_info->fhss_api || !fhss_configuration) {
00551         return -1;
00552     }
00553     // Set the LLC information to follow the actual fhss settings
00554     ws_bootstrap_llc_hopping_update(cur, fhss_configuration);
00555 
00556     // Set neighbor info callback
00557     if (ns_fhss_set_neighbor_info_fp(cur->ws_info->fhss_api, &ws_get_neighbor_info)) {
00558         return -1;
00559     }
00560     if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
00561         ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0);
00562     }
00563     return 0;
00564 }
00565 
00566 /* Sets the parent and broadcast schedule we are following
00567  *
00568  */
00569 static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, ws_parent_synch_e synch_req)
00570 {
00571 
00572     fhss_ws_configuration_t fhss_configuration;
00573     if (!neighbor_info->ws_neighbor->broadcast_timing_info_stored) {
00574         tr_error("No BC timing info for set new parent");
00575         return;
00576     }
00577 
00578     memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t));
00579 
00580     // Learning broadcast network configuration
00581     if (neighbor_info->ws_neighbor->broadcast_shedule_info_stored) {
00582         if (synch_req != WS_EAPOL_PARENT_SYNCH) {
00583             ws_fhss_set_defaults(cur, &fhss_configuration);
00584         }
00585         fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_channel_function;
00586         if (fhss_configuration.ws_bc_channel_function == WS_FIXED_CHANNEL) {
00587             cur->ws_info->hopping_schdule.bc_fixed_channel = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.fixed_channel;
00588             cur->ws_info->fhss_bc_fixed_channel = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.fixed_channel;
00589         }
00590         fhss_configuration.bsi = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_schedule_id;
00591         fhss_configuration.fhss_bc_dwell_interval = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_dwell_interval;
00592         fhss_configuration.fhss_broadcast_interval = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_interval;
00593         fhss_configuration.broadcast_fixed_channel = cur->ws_info->fhss_bc_fixed_channel;
00594         neighbor_info->ws_neighbor->synch_done = true;
00595     }
00596 
00597     ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
00598 
00599     // We have broadcast schedule set up set the broadcast parent schedule
00600     ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64 , &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, synch_req != WS_PARENT_SOFT_SYNCH);
00601 
00602     // Update LLC to follow updated fhss settings
00603     ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
00604 }
00605 
00606 void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info)
00607 {
00608     if (cur->ws_info->configuration_learned || !neighbor_info->ws_neighbor->broadcast_shedule_info_stored || !neighbor_info->ws_neighbor->broadcast_timing_info_stored) {
00609         return;
00610     }
00611 
00612     if (ws_bootstrap_candidate_parent_get(cur, neighbor_info->neighbor->mac64 , false) == NULL) {
00613         return;
00614     }
00615 
00616     //Store Brodacst Shedule
00617     if (!neighbor_info->ws_neighbor->synch_done) {
00618         ws_bootstrap_primary_parent_set(cur, neighbor_info, WS_EAPOL_PARENT_SYNCH);
00619     } else {
00620         ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64 , &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, false);
00621     }
00622 }
00623 
00624 static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur)
00625 {
00626     // Configure EUI64 for MAC if missing
00627     uint8_t mac64[8];
00628     if (!cur->mac_api) {
00629         return;
00630     }
00631 
00632     cur->mac_api->mac64_get(cur->mac_api, MAC_EXTENDED_DYNAMIC, mac64);
00633 
00634     if (memcmp(mac64, ADDR_UNSPECIFIED, 8) == 0) {
00635         cur->mac_api->mac64_get(cur->mac_api, MAC_EXTENDED_READ_ONLY, mac64);
00636     }
00637 
00638     if (memcmp(mac64, ADDR_UNSPECIFIED, 8) == 0) {
00639         // Generate random mac because it was not available
00640         randLIB_get_n_bytes_random(mac64, 8);
00641         mac64[0] |= 2; //Set Local Bit
00642         mac64[0] &= ~1; //Clear multicast bit
00643 
00644         tr_info("Generated random MAC %s", trace_array(mac64, 8));
00645     }
00646     mac_helper_mac64_set(cur, mac64);
00647 
00648     memcpy(cur->iid_eui64, mac64, 8);
00649     /* Invert U/L Bit */
00650     cur->iid_eui64[0] ^= 2;
00651     memcpy(cur->iid_slaac, cur->iid_eui64, 8);
00652 
00653 }
00654 
00655 /* \return 0x0100 to 0xFFFF ETX value (8 bit fraction)
00656  * \return 0xFFFF address not associated
00657  * \return 0x0000 address unknown or other error
00658  * \return 0x0001 no ETX statistics on this interface
00659  */
00660 uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr_type, const uint8_t *addr_ptr)
00661 {
00662 
00663     uint16_t etx;
00664     if (!addr_ptr || !interface) {
00665         return 0;
00666     }
00667 
00668     uint8_t attribute_index;
00669 
00670     mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), addr_ptr + PAN_ID_LEN, addr_type);
00671     if (!mac_neighbor) {
00672         return 0xffff;
00673     }
00674     attribute_index = mac_neighbor->index ;
00675     ws_neighbor_class_entry_t *ws_neighbour = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, attribute_index);
00676     etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, attribute_index);
00677 
00678     if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
00679         if (!ws_neighbour || !etx_entry) {
00680             return 0xffff;
00681         }
00682     } else {
00683 
00684         if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 /*||
00685                 !ws_neighbour->candidate_parent*/) {
00686             // if RSL value is not good enough candidate parent flag is removed and device not accepted as parent
00687             //tr_debug("ws_etx_read not valid params");
00688             return 0xffff;
00689         }
00690 
00691         //If we are not following gbobal Broadcast synch
00692         if (!interface->ws_info->pan_information.use_parent_bs) {
00693             //We must know both information's here
00694             if (!ws_neighbour->broadcast_shedule_info_stored ||
00695                     !ws_neighbour->broadcast_timing_info_stored) {
00696                 return 0xffff;
00697             }
00698         } else {
00699             if (!ws_neighbour->broadcast_timing_info_stored) {
00700                 //Global shedule is stored already
00701                 tr_debug("ws_etx_read not valid NO BTI");
00702                 return 0xffff;
00703             }
00704         }
00705     }
00706 
00707     etx = etx_local_etx_read(interface->id, attribute_index);
00708     if (etx == 0) {
00709         return 0xffff;
00710     }
00711 
00712     //tr_debug("ws_etx_read etx:%d", etx);
00713     return etx;
00714 }
00715 bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry,  bool unicast, uint8_t seq)
00716 {
00717     (void)cur;
00718     (void)seq;
00719 
00720     if (unicast) {
00721         // Unicast NS is OK
00722         return false;
00723     }
00724     // Fail the resolution
00725     tr_warn("Link address lost for %s", trace_ipv6(entry->ip_address));
00726     ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, entry);
00727     // True means we skip the message sending
00728     return true;
00729 }
00730 
00731 static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
00732 {
00733     int8_t ret_val = -1;
00734 
00735     if (!cur) {
00736         return -1;
00737     }
00738 
00739     if ((cur->configure_flags & INTERFACE_SETUP_MASK) != INTERFACE_SETUP_READY) {
00740         tr_error("Interface not yet fully configured");
00741         return -2;
00742     }
00743     if (ws_fhss_initialize(cur) != 0) {
00744         tr_error("fhss initialization failed");
00745         return -3;
00746     }
00747 
00748     // Save FHSS api
00749     cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
00750 
00751     ws_bootstrap_ll_address_validate(cur);
00752 
00753     addr_interface_set_ll64(cur, NULL);
00754     cur->nwk_nd_re_scan_count = 0;
00755     //WS_interface_up(cur);
00756     // Trigger discovery for bootstrap
00757     ret_val = nwk_6lowpan_up(cur);
00758     if (ret_val) {
00759         goto cleanup;
00760     }
00761 
00762     /* Disable SLLAO send/mandatory receive with the ARO */
00763     cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true;
00764     /* Omit sending of NA if ARO SUCCESS */
00765     cur->ipv6_neighbour_cache.omit_na_aro_success = true;
00766     /* Omit sending of NA and consider ACK to be success */
00767     cur->ipv6_neighbour_cache.omit_na = true;
00768     // do not process AROs from NA. This is overriden by Wi-SUN specific failure handling
00769     cur->ipv6_neighbour_cache.recv_na_aro = false;
00770     /* Disable NUD Probes */
00771     cur->ipv6_neighbour_cache.send_nud_probes = false;
00772     cur->ipv6_neighbour_cache.probe_avoided_routers = true;
00773     /*Replace NS handler to disable multicast address queries */
00774     cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit;
00775 
00776     dhcp_client_init(cur->id, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE);
00777     dhcp_client_configure(cur->id, true, true, true); //RENEW uses SOLICIT, Interface will use 1 instance for address get, IAID address hint is not used.
00778     dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC);
00779 
00780 
00781     ws_nud_table_reset(cur);
00782 
00783     ws_bootstrap_candidate_table_reset(cur);
00784 
00785     blacklist_params_set(
00786         WS_BLACKLIST_ENTRY_LIFETIME,
00787         WS_BLACKLIST_TIMER_MAX_TIMEOUT,
00788         WS_BLACKLIST_TIMER_TIMEOUT,
00789         WS_BLACKLIST_ENTRY_MAX_NBR,
00790         WS_BLACKLIST_PURGE_NBR,
00791         WS_BLACKLIST_PURGE_TIMER_TIMEOUT);
00792 
00793     ws_bootstrap_event_discovery_start(cur);
00794 
00795     return 0;
00796 cleanup:
00797     return ret_val;
00798 }
00799 
00800 static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur)
00801 {
00802     if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
00803         return -1;
00804     }
00805 
00806     tr_debug("Wi-SUN ifdown");
00807 
00808     // Reset WS information
00809     // ws_common_reset(cur)
00810     ws_llc_reset(cur);
00811     if (nd_proxy_downstream_interface_unregister(cur->id) != 0) {
00812         tr_warn("nd proxy unregister failed");
00813     }
00814     ws_nud_table_reset(cur);
00815     dhcp_client_delete(cur->id);
00816     ws_eapol_relay_delete(cur);
00817     ws_eapol_auth_relay_delete(cur);
00818     ws_pae_controller_stop(cur);
00819     ws_bootstrap_candidate_table_reset(cur);
00820     blacklist_clear();
00821 
00822     return nwk_6lowpan_down(cur);
00823 }
00824 
00825 void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur)
00826 {
00827     // Configure IP stack to operate as Wi-SUN node
00828 
00829     // Do not process beacons
00830     cur->mac_parameters->beacon_ind = NULL;
00831     cur->mac_parameters->mac_security_level = 0;
00832 
00833     // Set default parameters to interface
00834     cur->configure_flags = INTERFACE_BOOTSTRAP_DEFINED;
00835     cur->configure_flags |= INTERFACE_SECURITY_DEFINED;
00836     cur->lowpan_info = 0;
00837 
00838     switch (cur->bootsrap_mode) {
00839         //        case NET_6LOWPAN_SLEEPY_HOST:
00840         case ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST:
00841             break;
00842 
00843         case ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER:
00844         case ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER:
00845             cur->lowpan_info |= INTERFACE_NWK_ROUTER_DEVICE;
00846             break;
00847 
00848         default:
00849             tr_err("Invalid bootstrap_mode");
00850     }
00851 
00852     cur->nwk_bootstrap_state = ER_ACTIVE_SCAN;
00853     cur->ws_info->network_pan_id = 0xffff;
00854     cur->ws_info->trickle_pas_running = false;
00855     cur->ws_info->trickle_pa_running = false;
00856     cur->ws_info->trickle_pcs_running = false;
00857     cur->ws_info->trickle_pc_running = false;
00858 
00859     //cur->mac_security_key_usage_update_cb = ws_management_mac_security_key_update_cb;
00860     return;
00861 }
00862 
00863 static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr)
00864 {
00865     if (!network_name_ptr || !ie_ext) {
00866         return false;
00867     }
00868 
00869     ws_wp_network_name_t network_name;
00870     if (!ws_wp_nested_network_name_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &network_name)) {
00871         tr_warn("No network name IE");
00872         return false;
00873     }
00874 
00875     if (network_name_ptr == NULL || strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) {
00876         return false;
00877     }
00878     return true;
00879 }
00880 
00881 static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information)
00882 {
00883     /* In Active state
00884      *
00885      * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and
00886      * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost
00887      * the same or worse than (bigger than or equal to) that of the receiving node.
00888      *
00889      * Inconsistent:
00890      *
00891      * Received Routing Cost is smaller than stored one
00892      *
00893      * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching
00894      * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node.
00895      *
00896      */
00897 
00898 #ifdef WISUN_1_0_ERRATA_FIX
00899     // All messages are considered as consistent only Solicit will cause inconsistent
00900     trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
00901 #else
00902     // Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements
00903     if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) {
00904         trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
00905     } else {
00906         trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
00907     }
00908 #endif
00909 }
00910 
00911 static parent_info_t *ws_bootstrap_candidate_parent_get_best(protocol_interface_info_entry_t *cur)
00912 {
00913     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
00914         tr_info("candidate list a:%s panid:%x cost:%d size:%d rssi:%d age:%"PRIu32, trace_array(entry->addr, 8), entry->pan_id, entry->pan_information.routing_cost, entry->pan_information.pan_size, entry->signal_dbm, protocol_core_monotonic_time - entry->age);
00915     }
00916 
00917     return ns_list_get_first(&cur->ws_info->parent_list_reserved);
00918 }
00919 
00920 static void ws_bootstrap_candidate_parent_store(parent_info_t *parent, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information)
00921 {
00922     parent->ws_utt = *ws_utt;
00923     // Saved from unicast IE
00924     parent->ws_us = *ws_us;
00925 
00926     // Saved from Pan information, do not overwrite pan_version as it is not valid here
00927     parent->pan_information.pan_size = pan_information->pan_size;
00928     parent->pan_information.routing_cost = pan_information->routing_cost;
00929     parent->pan_information.use_parent_bs = pan_information->use_parent_bs;
00930     parent->pan_information.rpl_routing_method = pan_information->rpl_routing_method;
00931     parent->pan_information.version = pan_information->version;
00932 
00933     // Saved from message
00934     parent->timestamp = data->timestamp;
00935     parent->pan_id = data->SrcPANId;
00936     parent->link_quality = data->mpduLinkQuality;
00937     parent->signal_dbm = data->signal_dbm;
00938     memcpy(parent->addr, data->SrcAddr, 8);
00939 
00940     parent->age = protocol_core_monotonic_time;
00941 }
00942 
00943 static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur)
00944 {
00945     //Empty active list
00946     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_free) {
00947         ns_list_remove(&cur->ws_info->parent_list_free, entry);
00948     }
00949 
00950     //Empty free list
00951     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
00952         ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
00953     }
00954     //Add to free list to full
00955     for (int i = 0; i < WS_PARENT_LIST_SIZE; i++) {
00956         ns_list_add_to_end(&cur->ws_info->parent_list_free, &cur->ws_info->parent_info[i]);
00957     }
00958 }
00959 
00960 static parent_info_t *ws_bootstrap_candidate_parent_allocate(protocol_interface_info_entry_t *cur, const uint8_t *addr)
00961 {
00962     parent_info_t *entry = ns_list_get_first(&cur->ws_info->parent_list_free);
00963     if (entry) {
00964         memcpy(entry->addr, addr, 8);
00965         ns_list_remove(&cur->ws_info->parent_list_free, entry);
00966         ns_list_add_to_end(&cur->ws_info->parent_list_reserved, entry);
00967     } else {
00968         // If there is no free entries always allocate the last one of reserved as it is the worst
00969         entry = ns_list_get_last(&cur->ws_info->parent_list_reserved);
00970     }
00971     return entry;
00972 }
00973 
00974 static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, uint8_t *addr)
00975 {
00976     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
00977         if (memcmp(entry->addr, addr, 8) == 0) {
00978             ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
00979             ns_list_add_to_end(&cur->ws_info->parent_list_free, entry);
00980             return;
00981         }
00982     }
00983 }
00984 
00985 static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create)
00986 {
00987     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
00988         if (memcmp(entry->addr, addr, 8) == 0) {
00989             return entry;
00990         }
00991     }
00992     if (create) {
00993         return ws_bootstrap_candidate_parent_allocate(cur, addr);
00994     }
00995     return NULL;
00996 }
00997 
00998 static bool ws_bootstrap_candidate_parent_compare(parent_info_t *p1, parent_info_t *p2)
00999 {
01000     // Return true if P2 is better
01001     // signal lower than threshold for both
01002     // pan_cost
01003     // signal quality
01004 
01005     if (ws_neighbor_class_rsl_from_dbm_calculate(p1->signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) &&
01006             ws_neighbor_class_rsl_from_dbm_calculate(p2->signal_dbm) > (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) {
01007         // above threshold is always better than not.
01008         return true;
01009     }
01010     if (ws_neighbor_class_rsl_from_dbm_calculate(p2->signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) &&
01011             ws_neighbor_class_rsl_from_dbm_calculate(p1->signal_dbm) > (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) {
01012         // P2 is less than threshold and P1 is larger so P1 is always better.
01013         return false;
01014     }
01015 
01016     // Select the lowest PAN cost
01017     uint16_t p1_pan_cost = (p1->pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (p1->pan_information.pan_size / PS_WEIGHT_FACTOR);
01018     uint16_t p2_pan_cost = (p2->pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (p2->pan_information.pan_size / PS_WEIGHT_FACTOR);
01019     if (p1_pan_cost > p2_pan_cost) {
01020         return true;
01021     } else if (p1_pan_cost < p2_pan_cost) {
01022         return false;
01023     }
01024 
01025     // If pan cost is the same then we select the one we hear highest
01026     if (p1->signal_dbm < p2->signal_dbm) {
01027         return true;
01028     }
01029     return false;
01030 }
01031 
01032 static void ws_bootstrap_candidate_list_clean(struct protocol_interface_info_entry *cur, uint8_t pan_max, uint32_t current_time, uint16_t pan_id)
01033 {
01034     int pan_count = 0;
01035 
01036     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
01037         if ((current_time - entry->age) > WS_PARENT_LIST_MAX_AGE) {
01038             ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
01039             ns_list_add_to_end(&cur->ws_info->parent_list_free, entry);
01040             continue;
01041         }
01042         if (entry->pan_id == pan_id) {
01043             // Same panid if there is more than limited amount free those
01044             pan_count++;
01045             if (pan_count > pan_max) {
01046                 ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
01047                 ns_list_add_to_end(&cur->ws_info->parent_list_free, entry);
01048                 continue;
01049             }
01050         }
01051     }
01052 }
01053 
01054 static void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry)
01055 {
01056     ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
01057         if (entry == new_entry) {
01058             // own entry skip it
01059             continue;
01060         }
01061         if (ws_bootstrap_candidate_parent_compare(entry, new_entry)) {
01062             // New entry is better
01063             //tr_debug("candidate list new is better");
01064             ns_list_remove(&cur->ws_info->parent_list_reserved, new_entry);
01065             ns_list_add_before(&cur->ws_info->parent_list_reserved, entry, new_entry);
01066             return;
01067         }
01068     }
01069 }
01070 
01071 static void ws_bootstrap_pan_information_store(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information)
01072 {
01073 
01074     parent_info_t *new_entry;
01075     /* Have List of 20 heard neighbours
01076      * Order those as best based on pan cost
01077      * In single pan order based on signal quality
01078      * in single PAN limit the amount of devices to 5
01079      * If there is no advertisement heard for last hour Clear the neigbour.
01080      */
01081 
01082     // Discovery state processing
01083     //tr_info("neighbour: addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm);
01084 
01085     // Clean old entries
01086     ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY, protocol_core_monotonic_time, data->SrcPANId);
01087 
01088     new_entry = ws_bootstrap_candidate_parent_get(cur, data->SrcAddr, true);
01089     if (!new_entry) {
01090         tr_warn("neighbour creation fail");
01091         return;
01092     }
01093     // Safe the information
01094     ws_bootstrap_candidate_parent_store(new_entry, data, ws_utt, ws_us, pan_information);
01095     // set to the correct place in list
01096     ws_bootstrap_candidate_parent_sort(cur, new_entry);
01097 
01098     return;
01099 }
01100 
01101 static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
01102 {
01103 
01104     //Validate Pan Conrfirmation is at packet
01105     ws_pan_information_t pan_information;
01106     if (!ws_wp_nested_pan_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_information)) {
01107         // Corrupted
01108         tr_error("No pan information");
01109         return;
01110     }
01111 
01112     // Check pan flags so that it is valid
01113     if (!pan_information.rpl_routing_method) {
01114         // NOT RPL routing
01115         //tr_warn("Not supported routing");
01116         return;
01117     }
01118 
01119     // Store heard pans and possible candidate parents
01120     ws_bootstrap_pan_information_store(cur, data, ws_utt, ws_us, &pan_information);
01121 
01122     if (!(ws_bootstrap_state_active(cur) ||
01123             ws_bootstrap_state_wait_rpl(cur))) {
01124         // During discovery/eapol/config learn we dont do further processing for advertisements
01125         return;
01126     }
01127     // Active state processing
01128     //tr_debug("Advertisement active");
01129 
01130     // In active operation less neighbours per pan is allowed
01131     ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_ACTIVE, protocol_core_monotonic_time, data->SrcPANId);
01132 
01133     // Check if valid PAN
01134     if (data->SrcPANId != cur->ws_info->network_pan_id) {
01135         return;
01136     }
01137 
01138     // Save route cost for all known neighbors
01139     llc_neighbour_req_t neighbor_info;
01140     neighbor_info.neighbor = NULL;
01141     if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
01142         neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost;
01143     }
01144 
01145     ws_bootstrap_pan_advertisement_analyse_active(cur, &pan_information);
01146 
01147     // Learn latest network information
01148     if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) {
01149         uint8_t ll_address[16];
01150         ws_bootsrap_create_ll_address(ll_address, neighbor_info.neighbor->mac64 );
01151 
01152         if (rpl_control_is_dodag_parent(cur, ll_address)) {
01153             // automatic network size adjustment learned
01154             if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC &&
01155                     cur->ws_info->pan_information.pan_size != pan_information.pan_size) {
01156                 ws_common_network_size_configure(cur, pan_information.pan_size);
01157             }
01158 
01159             cur->ws_info->pan_information.pan_size = pan_information.pan_size;
01160             cur->ws_info->pan_information.routing_cost = pan_information.routing_cost;
01161             cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method;
01162             cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs;
01163             cur->ws_info->pan_information.version = pan_information.version;
01164         }
01165     }
01166 }
01167 
01168 static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
01169 {
01170 
01171     (void)data;
01172     (void)ws_utt;
01173     (void)ws_us;
01174     /*
01175      * An inconsistent transmission is defined as:
01176      * A PAN Advertisement Solicit with NETNAME-IE matching that of the receiving node.
01177      */
01178     trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
01179     /*
01180      *  A consistent transmission is defined as
01181      *  a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node.
01182      */
01183     trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit);
01184 
01185     /*
01186      *  Optimized PAN discovery to select faster the parent if we hear solicit from someone else
01187      */
01188 
01189     if (ws_bootstrap_state_discovery(cur) &&
01190             cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) {
01191         cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
01192         tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
01193     }
01194 }
01195 
01196 
01197 static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
01198 {
01199 
01200     uint16_t pan_version;
01201     ws_bs_ie_t ws_bs_ie;
01202     uint8_t *gtkhash_ptr;
01203 
01204     if (data->SrcPANId != cur->ws_info->network_pan_id) {
01205         return;
01206     }
01207     ws_bt_ie_t ws_bt_ie;
01208     if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) {
01209         tr_warn("BT-IE");
01210         return;
01211     }
01212 
01213     /*
01214      * A consistent transmission is defined as a PAN Configuration with a PAN-ID matching that of the receiving node and
01215      * a PANVER-IE / PAN Version greater than or equal to the receiving node’s current PAN version.
01216      *
01217      * A inconsistent transmission is defined as:
01218      *
01219      *  A PAN Configuration with PAN-ID matching that of the receiving node and a
01220      *  PANVER-IE / PAN Version that is less than the receiving node’s current PAN version.
01221      */
01222 
01223     // TODO Add this to neighbor table
01224     // TODO save all information from config message if version number has changed
01225 
01226     if (!ws_wp_nested_pan_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_version)) {
01227         // Corrupted
01228         tr_warn("no version");
01229         return;
01230     }
01231 
01232     gtkhash_ptr = ws_wp_nested_gtkhash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength);
01233 
01234     if (!gtkhash_ptr) {
01235         // Corrupted
01236         tr_error("No gtk hash");
01237         return;
01238     }
01239 
01240     if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) {
01241         // Corrupted
01242         tr_error("No broadcast schedule");
01243         return;
01244     }
01245     llc_neighbour_req_t neighbor_info;
01246     bool neighbour_pointer_valid;
01247 
01248     if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
01249         //If we are border router or learned configuration we only update already learned neighbours.
01250         neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false);
01251 
01252     } else {
01253         neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true);
01254         if (!neighbour_pointer_valid) {
01255             return;
01256         }
01257     }
01258 
01259     if (neighbour_pointer_valid) {
01260         etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index );
01261         //Update Neighbor Broadcast and Unicast Parameters
01262         ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp);
01263         ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us);
01264         ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp);
01265         ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie);
01266     }
01267 
01268     if (cur->ws_info->configuration_learned) {
01269         tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version);
01270         if (cur->ws_info->pan_information.pan_version == pan_version) {
01271             // Same version heard so it is consistent
01272             trickle_consistent_heard(&cur->ws_info->trickle_pan_config);
01273             if (neighbour_pointer_valid && neighbor_info.neighbor->link_role  == PRIORITY_PARENT_NEIGHBOUR) {
01274                 ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH);
01275             }
01276             // no need to process more
01277             return;
01278         } else  {
01279             // received version is different so we need to reset the trickle
01280             trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
01281             if (neighbour_pointer_valid && neighbor_info.neighbor->link_role  == PRIORITY_PARENT_NEIGHBOUR) {
01282                 ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH);
01283             }
01284             if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) {
01285                 // older version heard ignoring the message
01286                 return;
01287             }
01288         }
01289     }
01290 
01291     if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
01292         //Border router does not learn network information
01293         return;
01294     }
01295 
01296     /*
01297      * Learn new information from neighbor
01298      */
01299     tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version);
01300 
01301     // restart PAN version timer
01302     cur->ws_info->pan_version_timeout_timer = ws_common_version_timeout_get(cur->ws_info->network_size_config);
01303     cur->ws_info->pan_information.pan_version = pan_version;
01304 
01305     ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr);
01306 
01307     ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1);
01308 
01309     if (!cur->ws_info->configuration_learned) {
01310         // Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell
01311         tr_info("learn network configuration");
01312         cur->ws_info->configuration_learned = true;
01313         // return to state machine after 1-2 s
01314         cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20);
01315         // enable frequency hopping for unicast channel and start listening first neighbour
01316         ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH);
01317         // set neighbor as priority parent clear if there is others
01318         protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST);
01319         neighbor_info.neighbor->link_role  = PRIORITY_PARENT_NEIGHBOUR;
01320     }
01321 }
01322 
01323 static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
01324 {
01325     if (data->SrcPANId != cur->ws_info->network_pan_id) {
01326         return;
01327     }
01328 
01329     /* TODO smart neighbour process
01330      *
01331      * Unsecure packet we cant trust the device?
01332      *
01333      * Question mark in specification also present, now we create neighbour.
01334      * this is moved in future to NS/ND processing triggered by RPL
01335      *
01336      */
01337 
01338     llc_neighbour_req_t neighbor_info;
01339     if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
01340         etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index );
01341         ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp);
01342         ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us);
01343     }
01344 
01345 
01346 
01347     /*
01348      * A consistent transmission is defined as a PAN Configuration Solicit with
01349      * a PAN-ID matching that of the receiving node and a NETNAME-IE / Network Name
01350      * matching that configured on the receiving node.
01351      */
01352     trickle_consistent_heard(&cur->ws_info->trickle_pan_config_solicit);
01353     /*
01354      *  inconsistent transmission is defined as either:
01355      *  A PAN Configuration Solicit with a PAN-ID matching that of the receiving node and
01356      *  a NETNAME-IE / Network Name matching the network name configured on the receiving
01357      */
01358     trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
01359 }
01360 static bool ws_channel_plan_zero_compare(ws_channel_plan_zero_t *rx_plan, ws_hopping_schedule_t *hopping_schdule)
01361 {
01362     if (rx_plan->operation_class != hopping_schdule->operating_class) {
01363         return false;
01364     } else if (rx_plan->regulator_domain != hopping_schdule->regulatory_domain) {
01365         return false;
01366     }
01367     return true;
01368 }
01369 
01370 static bool ws_channel_plan_one_compare(ws_channel_plan_one_t *rx_plan, ws_hopping_schedule_t *hopping_schdule)
01371 {
01372     uint16_t num_of_channel = hopping_schdule->number_of_channels;
01373     if (rx_plan->ch0 != hopping_schdule->ch0_freq) {
01374         return false;
01375     } else if (rx_plan->channel_spacing != hopping_schdule->channel_spacing) {
01376         return false;
01377     } else if (rx_plan->number_of_channel != num_of_channel) {
01378         return false;
01379     }
01380     return true;
01381 }
01382 
01383 
01384 
01385 
01386 static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type)
01387 {
01388 
01389     if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) {
01390         // Not from long address
01391         return;
01392     }
01393     //Validate network name
01394     switch (message_type) {
01395         case WS_FT_PAN_ADVERT:
01396         case WS_FT_PAN_ADVERT_SOL:
01397         case WS_FT_PAN_CONF_SOL:
01398             //Check Network Name
01399             if (!ws_bootstrap_network_name_matches(ie_ext, cur->ws_info->network_name)) {
01400                 // Not in our network
01401                 return;
01402             }
01403             break;
01404         case WS_FT_PAN_CONF:
01405             break;
01406         default:
01407             return;
01408     }
01409     ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1);
01410     //UTT-IE and US-IE are mandatory for all Asynch Messages
01411     ws_utt_ie_t ws_utt;
01412     if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) {
01413         // Corrupted
01414         return;
01415     }
01416 
01417     ws_us_ie_t ws_us;
01418     if (!ws_wp_nested_us_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_us)) {
01419         // Corrupted
01420         return;
01421     }
01422 
01423     //Compare Unicast channel Plan
01424     if (ws_us.channel_plan != cur->ws_info->hopping_schdule.channel_plan) {
01425         return;
01426     }
01427 
01428     if (ws_us.channel_plan == 0) {
01429         if (!ws_channel_plan_zero_compare(&ws_us.plan.zero, &cur->ws_info->hopping_schdule)) {
01430             return;
01431         }
01432     } else if (ws_us.channel_plan == 1) {
01433         if (!ws_channel_plan_one_compare(&ws_us.plan.one, &cur->ws_info->hopping_schdule)) {
01434             return;
01435         }
01436     }
01437 
01438     //Handle Message's
01439     switch (message_type) {
01440         case WS_FT_PAN_ADVERT:
01441             // Analyse Advertisement
01442             tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm);
01443             ws_bootstrap_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
01444             break;
01445         case WS_FT_PAN_ADVERT_SOL:
01446             tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
01447             ws_bootstrap_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us);
01448             break;
01449         case WS_FT_PAN_CONF:
01450             tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
01451             ws_bootstrap_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
01452             break;
01453         default:
01454             tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
01455             ws_bootstrap_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us);
01456             break;
01457     }
01458 }
01459 
01460 static void ws_bootstrap_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message)
01461 {
01462     ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1);
01463     (void)interface;
01464     (void)asynch_message;
01465 }
01466 
01467 uint32_t ws_time_from_last_unicast_traffic(uint32_t current_time_stamp, ws_neighbor_class_entry_t *ws_neighbor)
01468 {
01469     uint32_t time_from_last_unicast_shedule = current_time_stamp;
01470 
01471     //Time from last RX unicast in us
01472     time_from_last_unicast_shedule -= ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp;
01473     time_from_last_unicast_shedule /= 1000000; //Convert to seconds
01474     return time_from_last_unicast_shedule;
01475 }
01476 
01477 static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_entry *interface)
01478 {
01479     uint8_t ll_target[16];
01480 
01481     if (mac_neighbor_info(interface)->neighbour_list_size <= mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT) {
01482         // Enough neighbor entries
01483         return;
01484     }
01485     memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8);
01486 
01487     uint32_t current_time_stamp = ns_sw_mac_read_current_timestamp(interface->mac_api);
01488 
01489     mac_neighbor_table_entry_t *neighbor_entry_ptr = NULL;
01490     ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) {
01491         ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, cur->index);
01492 
01493         if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) {
01494             //This is our primary parent we cannot delete
01495             continue;
01496         }
01497 
01498         if (cur->nud_active || ws_neighbor->accelerated_etx_probe || ws_neighbor->negative_aro_send) {
01499             //If NUD process is active do not trig
01500             continue;
01501         }
01502 
01503         if (neighbor_entry_ptr && neighbor_entry_ptr->lifetime  < cur->lifetime) {
01504             // We have already shorter link entry found this cannot replace it
01505             continue;
01506         }
01507 
01508         if (cur->trusted_device) {
01509 
01510             if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) {
01511                 // We have registered entry so we have been selected as parent
01512                 continue;
01513             }
01514 
01515             memcpy(ll_target + 8, cur->mac64, 8);
01516             ll_target[8] ^= 2;
01517 
01518             if (rpl_control_is_dodag_parent(interface, ll_target)) {
01519                 // Possible parent is limited to 3 by default?
01520                 continue;
01521             }
01522         }
01523 
01524         //Read current timestamp
01525         uint32_t time_from_last_unicast_shedule = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor);
01526         uint32_t min_timeout;
01527         if (interface->ws_info->network_size_config == NETWORK_SIZE_LARGE) {
01528             min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE;
01529         } else {
01530             min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL;
01531         }
01532         if (time_from_last_unicast_shedule > min_timeout) {
01533             //Accept only Enough Old Device
01534             if (!neighbor_entry_ptr) {
01535                 //Accept first compare
01536                 neighbor_entry_ptr = cur;
01537             } else {
01538                 uint32_t compare_neigh_time = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor_entry_ptr->index ));
01539                 if (compare_neigh_time < time_from_last_unicast_shedule)  {
01540                     //Accept older RX timeout allways
01541                     neighbor_entry_ptr = cur;
01542                 }
01543             }
01544         }
01545     }
01546     if (neighbor_entry_ptr) {
01547         tr_info("dropped oldest neighbour %s", trace_array(neighbor_entry_ptr->mac64 , 8));
01548         mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_entry_ptr);
01549     }
01550 
01551 }
01552 
01553 static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new)
01554 {
01555     neighbor_buffer->ws_neighbor = NULL;
01556     neighbor_buffer->neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), mac_64, ADDR_802_15_4_LONG );
01557     if (neighbor_buffer->neighbor) {
01558         neighbor_buffer->ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor_buffer->neighbor->index );
01559         if (!neighbor_buffer->ws_neighbor) {
01560             return false;
01561         }
01562         return true;
01563     }
01564     if (!request_new) {
01565         return false;
01566     }
01567 
01568     uint8_t ll_target[16];
01569     ws_bootsrap_create_ll_address(ll_target, mac_64);
01570 
01571     if (blacklist_reject(ll_target)) {
01572         // Rejected by blacklist
01573         return false;
01574     }
01575 
01576     ws_bootstrap_neighbor_table_clean(interface);
01577 
01578     neighbor_buffer->neighbor = ws_bootstrap_mac_neighbor_add(interface, mac_64);
01579 
01580     if (!neighbor_buffer->neighbor) {
01581         return false;
01582     }
01583 
01584     neighbor_buffer->ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor_buffer->neighbor->index );
01585     if (!neighbor_buffer->ws_neighbor) {
01586         mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_buffer->neighbor);
01587         return false;
01588     }
01589     return true;
01590 }
01591 
01592 static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface)
01593 {
01594     uint16_t parent_candidate_size = rpl_control_parent_candidate_list_size(interface, false);
01595     //TODO check bootstarap state for review
01596     //if we have enough candidates at list do not accept new multicast neighbours
01597     if (parent_candidate_size > interface->ws_info->rpl_parent_candidate_max) {
01598         return false;
01599     }
01600 
01601     parent_candidate_size = rpl_control_parent_candidate_list_size(interface, true);
01602     //If we have already enough parent selected Candidates count is bigger than configured
01603     if (parent_candidate_size >= interface->ws_info->rpl_selected_parent_max) {
01604         return false;
01605     }
01606 
01607     return true;
01608 }
01609 
01610 
01611 static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
01612 {
01613 
01614     protocol_interface_info_entry_t *cur = user_data;
01615     lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr);
01616     // Sleepy host
01617     if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
01618         mac_data_poll_protocol_poll_mode_decrement(cur);
01619     }
01620 
01621     //TODO State machine check here
01622 
01623     if (entry_ptr->ffd_device ) {
01624         protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_ptr->mac16 );
01625         protocol_6lowpan_release_long_link_address_from_neighcache(cur, entry_ptr->mac64 );
01626     }
01627 
01628     //NUD Process Clear Here
01629     ws_nud_entry_remove(cur, entry_ptr);
01630 
01631     ws_bootstrap_neighbor_delete(cur, entry_ptr);
01632 }
01633 
01634 static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
01635 {
01636     uint32_t time_from_start = entry_ptr->link_lifetime  - entry_ptr->lifetime ;
01637     bool activate_nud = false;
01638     protocol_interface_info_entry_t *cur = user_data;
01639 
01640     ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, entry_ptr->index );
01641     etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, entry_ptr->index );
01642 
01643     if (!entry_ptr->trusted_device  || !ws_neighbor || !etx_entry || ws_neighbor->negative_aro_send) {
01644         return false;
01645     }
01646 
01647     uint8_t ll_address[16];
01648 
01649     if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) {
01650 
01651         ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64 );
01652 
01653         if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
01654             if (!ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64 )) {
01655                 //NUD Not needed for if neighbour is not child or parent candidate
01656                 return false;
01657             }
01658         }
01659 
01660         if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) {
01661             activate_nud = true;
01662         } else {
01663             uint16_t switch_prob = randLIB_get_random_in_range(0, WS_NUD_RANDOM_SAMPLE_LENGTH - 1);
01664             //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5
01665             if (switch_prob < WS_NUD_RANDOM_COMPARE) {
01666                 activate_nud = true;
01667             }
01668         }
01669     } else if (etx_entry->etx_samples < WS_NEIGBOR_ETX_SAMPLE_MAX) {
01670         //Take Random number for trig a prope.
01671         //ETX Sample 0: random 1-8
01672         //ETX Sample 1: random 2-16
01673         //ETX Sample 2: random 4-32
01674         if (etx_entry->etx_samples == 0 && ws_neighbor->accelerated_etx_probe) {
01675             //Accept quick Probe for init ETX
01676             activate_nud = true;
01677         } else {
01678 
01679             ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64 );
01680             if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
01681                 return false;
01682             }
01683 
01684             uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples;
01685             uint32_t time_block = 1 << etx_entry->etx_samples;
01686             if (time_from_start >= probe_period) {
01687                 //tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples);
01688                 activate_nud = true;
01689             } else if (time_from_start > time_block) {
01690                 uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1);
01691                 //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5
01692                 if (switch_prob < 2) {
01693                     //tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples);
01694                     activate_nud = true;
01695                 }
01696             }
01697         }
01698     }
01699 
01700     if (!activate_nud) {
01701         return false;
01702     }
01703 
01704     ws_nud_table_entry_t *entry = ws_nud_entry_get_free(cur);
01705     if (!entry) {
01706         return false;
01707     }
01708     entry->neighbor_info = entry_ptr;
01709     if (ws_neighbor->accelerated_etx_probe) {
01710         ws_neighbor->accelerated_etx_probe = false;
01711         entry->timer = 1;
01712     }
01713 
01714     if (etx_entry->etx_samples >= WS_NEIGBOR_ETX_SAMPLE_MAX) {
01715         entry->nud_process = true;
01716     }
01717     return true;
01718 }
01719 
01720 int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
01721 {
01722     int ret_val = 0;
01723 
01724     ws_neighbor_class_t neigh_info;
01725     neigh_info.neigh_info_list  = NULL;
01726     neigh_info.list_size  = 0;
01727     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
01728     if (!cur) {
01729         return -1;
01730     }
01731 
01732     mac_description_storage_size_t buffer;
01733     if (!cur->mac_api || !cur->mac_api->mac_storage_sizes_get || cur->mac_api->mac_storage_sizes_get(cur->mac_api, &buffer) != 0) {
01734         return -2;
01735     }
01736 
01737     if (buffer.key_description_table_size < 4) {
01738         tr_err("MAC key_description_table_size too short %d<4", buffer.key_description_table_size);
01739         return -2;
01740     }
01741 
01742     if (ns_sw_mac_enable_frame_counter_per_key(cur->mac_api, true)) {
01743         return -1;
01744     }
01745 
01746     if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) {
01747         return -1;
01748     }
01749     if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT)) {
01750         etx_storage_list_allocate(cur->id, 0);
01751         return -1;
01752     }
01753 
01754     etx_max_update_set(WS_ETX_MAX_UPDATE);
01755 
01756     if (blacklist_init() != 0) {
01757         tr_err("MLE blacklist init failed.");
01758         return -1;
01759     }
01760 
01761     switch (bootstrap_mode) {
01762         //        case NET_6LOWPAN_SLEEPY_HOST:
01763         case NET_6LOWPAN_HOST:
01764             cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST;
01765             break;
01766         case NET_6LOWPAN_ROUTER:
01767             cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER;
01768             break;
01769         case NET_6LOWPAN_BORDER_ROUTER:
01770             cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER;
01771             break;
01772         default:
01773             return -3;
01774     }
01775 
01776     if (!ws_neighbor_class_alloc(&neigh_info, buffer.device_decription_table_size)) {
01777         ret_val = -1;
01778         goto init_fail;
01779     }
01780 
01781     //Disable allways by default
01782     lowpan_adaptation_interface_mpx_register(interface_id, NULL, 0);
01783 
01784     mac_neighbor_table_delete(mac_neighbor_info(cur));
01785     mac_neighbor_info(cur) = mac_neighbor_table_create(buffer.device_decription_table_size, ws_neighbor_entry_remove_notify
01786                                                        , ws_neighbor_entry_nud_notify, cur);
01787     if (!mac_neighbor_info(cur)) {
01788         ret_val = -1;
01789         goto init_fail;
01790     }
01791 
01792     ws_llc_create(cur, &ws_bootstrap_asynch_ind, &ws_bootstrap_asynch_confirm, &ws_bootstrap_neighbor_info_request);
01793 
01794     mpx_api_t *mpx_api = ws_llc_mpx_api_get(cur);
01795     if (!mpx_api) {
01796         ret_val =  -4;
01797         goto init_fail;
01798     }
01799 
01800     if (ws_common_allocate_and_init(cur) < 0) {
01801         ret_val =  -4;
01802         goto init_fail;
01803     }
01804 
01805     if (ws_bootstrap_tasklet_init(cur) != 0) {
01806         ret_val =  -4;
01807         goto init_fail;
01808     }
01809 
01810     //Register MPXUser to adapatation layer
01811     if (lowpan_adaptation_interface_mpx_register(interface_id, mpx_api, MPX_LOWPAN_ENC_USER_ID) != 0) {
01812         ret_val =  -4;
01813         goto init_fail;
01814     }
01815 
01816     //Init PAE controller and set callback
01817     if (ws_pae_controller_init(cur) < 0) {
01818         ret_val =  -4;
01819         goto init_fail;
01820     }
01821     if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &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) < 0) {
01822         ret_val =  -4;
01823         goto init_fail;
01824     }
01825 
01826     //Init EAPOL PDU handler and register it to MPX
01827     if (ws_eapol_pdu_init(cur) < 0) {
01828         ret_val =  -4;
01829         goto init_fail;
01830     }
01831     if (ws_eapol_pdu_mpx_register(cur, mpx_api, MPX_KEY_MANAGEMENT_ENC_USER_ID != 0)) {
01832         ret_val =  -4;
01833         // add deallocs
01834         goto init_fail;
01835     }
01836 
01837     cur->if_up = ws_bootstrap_up;
01838     cur->if_down = ws_bootstrap_down;
01839     cur->ws_info->neighbor_storage = neigh_info;
01840     cur->etx_read_override = ws_etx_read;
01841 
01842     ws_bootstrap_configuration_reset(cur);
01843     addr_notification_register(ws_bootstrap_address_notification_cb);
01844     //Enable MAC Security by pass
01845     mlme_set_t set_req;
01846     bool state = true;
01847     set_req.attr = macAcceptByPassUnknowDevice;
01848     set_req.attr_index = 0;
01849     set_req.value_pointer = &state;
01850     set_req.value_size = sizeof(bool);
01851     cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
01852 
01853     // Set the default parameters for MPL
01854     cur->mpl_proactive_forwarding = true;
01855 
01856     cur->mpl_data_trickle_params.Imin = MPL_MS_TO_TICKS(DATA_MESSAGE_IMIN);
01857     cur->mpl_data_trickle_params.Imax = MPL_MS_TO_TICKS(DATA_MESSAGE_IMAX);
01858     cur->mpl_data_trickle_params.TimerExpirations = DATA_MESSAGE_TIMER_EXPIRATIONS;
01859     cur->mpl_data_trickle_params.k = 8;
01860 
01861     // Specification is ruling out the compression mode, but we are now doing it.
01862     cur->mpl_seed = true;
01863     cur->mpl_seed_id_mode = MULTICAST_MPL_SEED_ID_IPV6_SRC_FOR_DOMAIN;
01864     cur->mpl_seed_set_entry_lifetime = MPL_SEED_SET_ENTRY_TIMEOUT;
01865 
01866     cur->mpl_control_trickle_params.TimerExpirations = 0;
01867 
01868     mpl_domain_create(cur, ADDR_ALL_MPL_FORWARDERS, NULL, MULTICAST_MPL_SEED_ID_DEFAULT, -1, 0, NULL, NULL);
01869     addr_add_group(cur, ADDR_REALM_LOCAL_ALL_NODES);
01870     addr_add_group(cur, ADDR_REALM_LOCAL_ALL_ROUTERS);
01871 
01872     return 0;
01873 
01874     //Error handling and free memory
01875 init_fail:
01876     lowpan_adaptation_interface_mpx_register(interface_id, NULL, 0);
01877     ws_eapol_pdu_mpx_register(cur, NULL, 0);
01878     mac_neighbor_table_delete(mac_neighbor_info(cur));
01879     etx_storage_list_allocate(cur->id, 0);
01880     ws_neighbor_class_dealloc(&neigh_info);
01881     ws_llc_delete(cur);
01882     ws_eapol_pdu_delete(cur);
01883     ws_pae_controller_delete(cur);
01884     return ret_val;
01885 }
01886 
01887 int ws_bootstrap_restart(int8_t interface_id)
01888 {
01889     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
01890     if (!cur || !cur->ws_info) {
01891         return -1;
01892     }
01893     ws_bootstrap_event_discovery_start(cur);
01894     return 0;
01895 }
01896 
01897 int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s rf_configs)
01898 {
01899     mlme_set_t set_request;
01900     // Set RF configuration
01901     set_request.attr = macRfConfiguration;
01902     set_request.value_pointer = &rf_configs;
01903     set_request.value_size = sizeof(phy_rf_channel_configuration_s);
01904     cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
01905     // Set Ack wait duration
01906     uint16_t ack_wait_symbols = WS_ACK_WAIT_SYMBOLS + (WS_TACK_MAX_MS * (rf_configs.datarate / 1000));
01907     set_request.attr = macAckWaitDuration;
01908     set_request.value_pointer = &ack_wait_symbols;
01909     set_request.value_size = sizeof(ack_wait_symbols);
01910     cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
01911     // Set multi CSMA-CA configuration
01912     mlme_multi_csma_ca_param_t multi_csma_params = {WS_NUMBER_OF_CSMA_PERIODS, WS_CSMA_MULTI_CCA_INTERVAL};
01913     set_request.attr = macMultiCSMAParameters;
01914     set_request.value_pointer = &multi_csma_params;
01915     set_request.value_size = sizeof(mlme_multi_csma_ca_param_t);
01916     cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
01917     return 0;
01918 }
01919 
01920 int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
01921 {
01922     mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), ll_address, false, NULL);
01923 
01924     if (mac_neighbor) {
01925         mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), mac_neighbor);
01926     }
01927     return 0;
01928 }
01929 
01930 int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
01931 {
01932     rpl_control_neighbor_delete(cur, ll_address);
01933     ws_bootstrap_neighbor_remove(cur, ll_address);
01934     return 0;
01935 }
01936 
01937 static void ws_bootstrap_mac_activate(protocol_interface_info_entry_t *cur, uint16_t channel, uint16_t panid, bool coordinator)
01938 {
01939     mlme_start_t start_req;
01940     memset(&start_req, 0, sizeof(mlme_start_t));
01941 
01942     cur->mac_parameters->pan_id = panid;
01943     cur->mac_parameters->mac_channel = channel;
01944 
01945     start_req.PANId = panid;
01946     start_req.LogicalChannel = channel;
01947     start_req.BeaconOrder = 0x0f;
01948     start_req.SuperframeOrder = 0x0f;
01949     start_req.PANCoordinator = coordinator;
01950 
01951     if (cur->mac_api) {
01952         cur->mac_api->mlme_req(cur->mac_api, MLME_START, (void *)&start_req);
01953     }
01954 }
01955 
01956 static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur)
01957 {
01958     tr_debug("FHSS activate");
01959     ws_fhss_enable(cur);
01960     ws_llc_hopping_schedule_config(cur, &cur->ws_info->hopping_schdule);
01961     // Only supporting fixed channel
01962 
01963     tr_debug("MAC init");
01964     mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, true);
01965     cur->lowpan_info &=  ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE;
01966     ws_bootstrap_mac_security_enable(cur);
01967     ws_bootstrap_mac_activate(cur, cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->network_pan_id, true);
01968     return;
01969 }
01970 
01971 static void ws_bootstrap_network_configuration_learn(protocol_interface_info_entry_t *cur)
01972 {
01973     tr_debug("Start using PAN configuration");
01974 
01975     // Timing information can be modified here
01976     ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information);
01977     uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
01978     ws_llc_set_gtkhash(cur, gtkhash);
01979     // TODO update own fhss schedules we are starting to follow first parent
01980 
01981     return;
01982 }
01983 
01984 static void ws_bootstrap_ip_stack_addr_clear(protocol_interface_info_entry_t *cur)
01985 {
01986     tr_debug("ip stack address clear");
01987     ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) {
01988         if (addr->source != ADDR_SOURCE_STATIC &&
01989                 addr_ipv6_scope(addr->address, cur) > IPV6_SCOPE_LINK_LOCAL) {
01990             // Remove all exept User set address
01991             addr_delete_entry(cur, addr);
01992         }
01993     }
01994 }
01995 
01996 static void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur)
01997 {
01998     tr_debug("ip stack reset");
01999     // Delete all temporary cached information
02000     ipv6_neighbour_cache_flush(&cur->ipv6_neighbour_cache);
02001     lowpan_context_list_free(&cur->lowpan_contexts);
02002 }
02003 
02004 static void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur)
02005 {
02006     tr_debug("ip stack init");
02007     clear_power_state(ICMP_ACTIVE);
02008     cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE;
02009     ws_bootstrap_ip_stack_reset(cur);
02010 }
02011 
02012 static void ws_set_fhss_hop(protocol_interface_info_entry_t *cur)
02013 {
02014     uint16_t own_rank = ws_bootstrap_rank_get(cur);
02015     uint16_t rank_inc = ws_bootstrap_min_rank_inc_get(cur);
02016     if (own_rank == 0xffff || rank_inc == 0xffff) {
02017         return;
02018     }
02019     // Calculate own hop count. This method gets inaccurate when hop count increases.
02020     uint8_t own_hop = (own_rank - rank_inc) / rank_inc;
02021     ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, own_hop);
02022     tr_debug("own hop: %u, own rank: %u, rank inc: %u", own_hop, own_rank, rank_inc);
02023 }
02024 
02025 static void ws_address_registration_update(protocol_interface_info_entry_t *interface)
02026 {
02027     rpl_control_register_address(interface, NULL);
02028     tr_info("RPL parent update ... register ARO");
02029 }
02030 
02031 static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle)
02032 {
02033 
02034     protocol_interface_info_entry_t *cur = handle;
02035     if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) {
02036         return;
02037     }
02038     // if waiting for RPL and
02039     if (event == RPL_EVENT_DAO_DONE) {
02040         // Trigger statemachine check
02041         cur->bootsrap_state_machine_cnt = 1;
02042         rpl_dodag_info_t dodag_info;
02043         struct rpl_instance *instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL);
02044 
02045         if (instance && rpl_control_read_dodag_info(instance, &dodag_info)) {
02046             tr_debug("Enable DHCPv6 relay");
02047             dhcp_relay_agent_enable(cur->id, dodag_info.dodag_id);
02048 
02049             tr_debug("Start EAPOL relay");
02050             // Set both own port and border router port to 10253
02051             ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT);
02052             // Set network information to PAE
02053             ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
02054             // Network key is valid
02055             ws_pae_controller_nw_key_valid(cur);
02056         }
02057 
02058         ws_set_fhss_hop(cur);
02059 
02060     } else if (event == RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS) {
02061         /*
02062          * RPL goes to passive mode, but does not require any extra changed
02063          *
02064          * We could remove our current addresses learned from RPL
02065          * We could send solicit for configuration and then select new parent when those arrive
02066          *
02067          */
02068 
02069     } else if (event == RPL_EVENT_DAO_PARENT_ADD) {
02070         ws_address_registration_update(cur);
02071     }
02072     cur->ws_info->rpl_state = event;
02073     tr_info("RPL event %d", event);
02074 }
02075 
02076 static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status)
02077 {
02078     (void)prefix;
02079     (void)interface;
02080     //TODO add handler for negative status
02081     tr_debug("DHCPv6 %s status %u with link %s", trace_ipv6(prefix), register_status, trace_ipv6(dhcp_addr));
02082     if (register_status) {
02083         protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface);
02084         if (cur) {
02085             rpl_control_register_address(cur, prefix);
02086         }
02087     } else {
02088         //Delete dhcpv6 client
02089         dhcp_client_global_address_delete(interface, dhcp_addr, prefix);
02090     }
02091 }
02092 
02093 
02094 void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local)
02095 {
02096     if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, ws_dhcp_client_global_adress_cb) != 0) {
02097         tr_error("DHCPp client request fail");
02098     }
02099 }
02100 
02101 void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix)
02102 {
02103     dhcp_client_global_address_delete(cur->id, NULL, prefix);
02104 }
02105 
02106 bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur)
02107 {
02108     if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) {
02109         return true;
02110     }
02111 
02112     return false;
02113 }
02114 
02115 static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local)
02116 {
02117     protocol_interface_info_entry_t *cur = (protocol_interface_info_entry_t *) handle;
02118     /* Check if A-Flag.
02119      * A RPL node may use this option for the purpose of Stateless Address Autoconfiguration (SLAAC)
02120      * from a prefix advertised by a parent.
02121      */
02122     if (prefix->options & PIO_A) {
02123 
02124         if (parent_link_local) {
02125             if (icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime) != 0) {
02126                 ipv6_interface_slaac_handler(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime);
02127                 /*
02128                  * Give SLAAC addresses a different label and low precedence to indicate that
02129                  * they probably shouldn't be used for external traffic. SLAAC use in Wi-SUN is non-standard,
02130                  * and we use it for mesh-local traffic we should prefer any DHCP-assigned addresses
02131                  * for talking to the outside world
02132                  *
02133                  */
02134                 addr_policy_table_add_entry(prefix->prefix, prefix->prefix_len, 2, WS_NON_PREFFRED_LABEL);
02135             }
02136         } else {
02137             icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, 0, 0);
02138         }
02139     } else if (prefix->prefix_len) {
02140         // Create new address using DHCP
02141         if (parent_link_local) {
02142             ws_dhcp_client_address_request(cur, prefix->prefix, parent_link_local);
02143         } else {
02144             /* Deprecate address and remove client */
02145             tr_debug("Prefix invalidation %s", trace_ipv6(prefix->prefix));
02146             dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix);
02147         }
02148     }
02149 }
02150 
02151 static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle)
02152 {
02153 
02154     protocol_interface_info_entry_t *cur = handle;
02155     if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) {
02156         return false;
02157     }
02158 
02159     uint8_t mac64[8];
02160     memcpy(mac64, ll_parent_address + 8, 8);
02161     mac64[0] ^= 2;
02162     llc_neighbour_req_t neigh_buffer;
02163     if (ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false)) {
02164         return true;
02165     }
02166 
02167     if (!ws_rpl_dio_new_parent_accept(cur)) {
02168         return false;
02169     }
02170 
02171     //Discover Multicast temporary entry
02172 
02173     ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64);
02174     if (!entry) {
02175         return false;
02176     }
02177     //Create entry
02178     bool create_ok = ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, true);
02179     if (create_ok) {
02180         ws_neighbor_class_entry_t *ws_neigh = neigh_buffer.ws_neighbor;
02181         //Copy fhss temporary data
02182         *ws_neigh = entry->neigh_info_list ;
02183         //ETX Create here
02184         etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index );
02185         mac_neighbor_table_trusted_neighbor(mac_neighbor_info(cur), neigh_buffer.neighbor, true);
02186     }
02187     ws_llc_free_multicast_temp_entry(cur, entry);
02188 
02189 
02190     return create_ok;
02191 }
02192 
02193 static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur)
02194 {
02195     tr_debug("RPL Activate");
02196     bool downstream = true;
02197     bool leaf = false;
02198 
02199     addr_add_router_groups(cur);
02200     rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, downstream);
02201     rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback_t, cur);
02202     // If i am router I Do this
02203     rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf);
02204     rpl_control_request_parent_link_confirmation(true);
02205     rpl_control_set_dio_multicast_min_config_advertisment_count(WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT);
02206     rpl_control_set_dao_retry_count(WS_MAX_DAO_RETRIES);
02207     rpl_control_set_initial_dao_ack_wait(WS_MAX_DAO_INITIAL_TIMEOUT);
02208 
02209     cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event
02210 }
02211 
02212 static void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur)
02213 {
02214     //Set Network names, Pan information configure, hopping schedule & GTKHash
02215     ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name));
02216     ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information);
02217 }
02218 
02219 static void ws_bootstrap_network_discovery_configure(protocol_interface_info_entry_t *cur)
02220 {
02221     // Reset information to defaults
02222     cur->ws_info->network_pan_id = 0xffff;
02223 
02224     ws_common_regulatory_domain_config(cur);
02225     ws_fhss_discovery_configure(cur);
02226 
02227     //Set Network names, Pan information configure, hopping schedule & GTKHash
02228     ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name));
02229 }
02230 
02231 
02232 static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur)
02233 {
02234     cur->ws_info->trickle_pa_running = true;
02235     trickle_start(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
02236     cur->ws_info->trickle_pc_running = true;
02237     trickle_start(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
02238 }
02239 
02240 static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur)
02241 {
02242     cur->ws_info->pan_version_timer = 1;
02243 }
02244 
02245 // Start network scan
02246 static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
02247 {
02248     tr_debug("router discovery start");
02249     // Remove network keys from MAC
02250     ws_pae_controller_nw_keys_remove(cur);
02251     ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN);
02252     cur->nwk_nd_re_scan_count = 0;
02253     cur->ws_info->configuration_learned = false;
02254     cur->ws_info->pan_version_timeout_timer = 0;
02255 
02256     // Clear learned neighbours
02257     ws_bootstrap_neighbor_list_clean(cur);
02258 
02259     // Clear learned candidate parents
02260     ws_bootstrap_candidate_table_reset(cur);
02261 
02262     // Clear RPL information
02263     rpl_control_free_domain_instances_from_interface(cur);
02264     // Clear EAPOL relay address
02265     ws_eapol_relay_delete(cur);
02266 
02267     // Clear ip stack from old information
02268     ws_bootstrap_ip_stack_reset(cur);
02269     // New network scan started old addresses not assumed valid anymore
02270     ws_bootstrap_ip_stack_addr_clear(cur);
02271 
02272     if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) {
02273         // we have sent bootstrap ready event and now
02274         // restarted discovery so bootstrap down event is sent
02275         cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE;
02276         ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN);
02277     }
02278 
02279     // Start advertisement solicit trickle and calculate when we are checking the status
02280     cur->ws_info->trickle_pas_running = true;
02281     if (cur->ws_info->trickle_pan_advertisement_solicit.I != cur->ws_info->trickle_params_pan_discovery.Imin) {
02282         // Trickle not reseted so starting a new interval
02283         trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
02284     }
02285 
02286     // Discovery statemachine is checkked after we have sent the Solicit
02287     uint16_t time_to_solicit = 0;
02288     if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) {
02289         time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now;
02290     }
02291 
02292     tr_debug("Disc params imin %u, imax %u, expirations %u, k %u PAS Trickle I %u t %u, now %u, c %u",
02293              cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k,
02294              cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c);
02295 
02296     cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
02297     tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
02298 }
02299 
02300 // Start authentication
02301 static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur)
02302 {
02303     // Set PAN ID and network name to controller
02304     ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
02305 
02306     ws_pae_controller_authenticate(cur);
02307 }
02308 
02309 static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur)
02310 {
02311     mac_helper_default_security_level_set(cur, AES_SECURITY_LEVEL_ENC_MIC64);
02312     mac_helper_default_security_key_id_mode_set(cur, MAC_KEY_ID_MODE_IDX);
02313 }
02314 
02315 static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t slot, uint8_t index, uint8_t *key)
02316 {
02317     mac_helper_security_key_to_descriptor_set(cur, key, index + 1, slot);
02318 }
02319 
02320 static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot)
02321 {
02322     mac_helper_security_key_descriptor_clear(cur, slot);
02323 }
02324 
02325 static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index)
02326 {
02327     // Set send key
02328     mac_helper_security_auto_request_key_index_set(cur, index, index + 1);
02329 }
02330 
02331 static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot)
02332 {
02333     // Set frame counter
02334     mac_helper_key_link_frame_counter_set(cur->id, counter, slot);
02335 }
02336 
02337 static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot)
02338 {
02339     // Read frame counter
02340     mac_helper_key_link_frame_counter_read(cur->id, counter, slot);
02341 }
02342 
02343 static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64)
02344 {
02345     (void) target_eui_64;
02346 
02347     if (result == AUTH_RESULT_OK) {
02348         tr_debug("authentication success");
02349         ws_bootstrap_event_configuration_start(cur);
02350     } else if (result == AUTH_RESULT_ERR_TX_NO_ACK) {
02351         // eapol parent selected is not working
02352         tr_debug("authentication TX failed");
02353 
02354         ws_bootstrap_candidate_parent_free(cur, target_eui_64);
02355         // Go back for network scanning
02356         ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN);
02357         cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, cur->ws_info->trickle_params_pan_discovery.Imin >> 1);
02358         tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
02359     } else {
02360         tr_debug("authentication failed");
02361         // What else to do to start over again...
02362         // Trickle is reseted when entering to discovery from state 2
02363         trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
02364         ws_bootstrap_event_discovery_start(cur);
02365     }
02366 }
02367 
02368 // Start configuration learning
02369 static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur)
02370 {
02371     tr_debug("router configuration learn start");
02372     ws_bootstrap_state_change(cur, ER_SCAN);
02373 
02374     cur->ws_info->configuration_learned = false;
02375 
02376     // Clear all temporary information
02377     ws_bootstrap_ip_stack_reset(cur);
02378 
02379     cur->ws_info->pas_requests = 0;
02380     // Reset advertisement solicit trickle to start discovering network
02381     cur->ws_info->trickle_pcs_running = true;
02382     trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery);
02383     trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery);
02384 }
02385 static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur)
02386 {
02387     tr_debug("Start RPL learn");
02388     // routers wait until RPL root is contacted
02389     ws_bootstrap_state_change(cur, ER_RPL_SCAN);
02390     // Set timeout for check to 30 -60 seconds
02391     cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT);
02392 }
02393 
02394 /*
02395  * Event transitions
02396  *
02397  * */
02398 void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur)
02399 {
02400     ws_bootsrap_event_trig(WS_DISCOVERY_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
02401 }
02402 void ws_bootstrap_event_configuration_start(protocol_interface_info_entry_t *cur)
02403 {
02404     ws_bootsrap_event_trig(WS_CONFIGURATION_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
02405 }
02406 void ws_bootstrap_event_authentication_start(protocol_interface_info_entry_t *cur)
02407 {
02408     ws_bootstrap_state_change(cur, ER_PANA_AUTH);
02409 }
02410 void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur)
02411 {
02412     ws_bootsrap_event_trig(WS_OPERATION_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
02413 }
02414 void ws_bootstrap_event_routing_ready(protocol_interface_info_entry_t *cur)
02415 {
02416     ws_bootsrap_event_trig(WS_ROUTING_READY, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
02417 }
02418 void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *cur)
02419 {
02420     trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
02421 }
02422 
02423 static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asynch_request_t *async_req)
02424 {
02425     memset(&async_req->channel_list, 0, sizeof(channel_list_s));
02426     if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) {
02427         //SET 1 Channel only
02428         uint16_t channel_number = cur->ws_info->fhss_uc_fixed_channel;
02429         async_req->channel_list.channel_mask[0 + (channel_number / 32)] = (1 << (channel_number % 32));
02430     } else {
02431         ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
02432     }
02433 
02434     async_req->channel_list.channel_page = CHANNEL_PAGE_10;
02435 }
02436 
02437 static void ws_bootstrap_pan_advert_solicit(protocol_interface_info_entry_t *cur)
02438 {
02439     asynch_request_t async_req;
02440     memset(&async_req, 0, sizeof(asynch_request_t));
02441     async_req.message_type = WS_FT_PAN_ADVERT_SOL;
02442     //Request UTT Header and US and Net name from payload
02443     async_req.wh_requested_ie_list.utt_ie = true;
02444     async_req.wp_requested_nested_ie_list.us_ie = true;
02445     async_req.wp_requested_nested_ie_list.net_name_ie = true;
02446 
02447     ws_set_asynch_channel_list(cur, &async_req);
02448 
02449 
02450     async_req.security.SecurityLevel = 0;
02451 
02452     ws_llc_asynch_request(cur, &async_req);
02453 }
02454 
02455 static void ws_bootstrap_pan_config_solicit(protocol_interface_info_entry_t *cur)
02456 {
02457     asynch_request_t async_req;
02458     memset(&async_req, 0, sizeof(asynch_request_t));
02459     async_req.message_type = WS_FT_PAN_CONF_SOL;
02460     //Request UTT Header and US and Net name from payload
02461     async_req.wh_requested_ie_list.utt_ie = true;
02462     async_req.wp_requested_nested_ie_list.us_ie = true;
02463     async_req.wp_requested_nested_ie_list.net_name_ie = true;
02464 
02465     ws_set_asynch_channel_list(cur, &async_req);
02466     async_req.security.SecurityLevel = 0;
02467 
02468     ws_llc_asynch_request(cur, &async_req);
02469 }
02470 
02471 static struct rpl_instance *ws_get_rpl_instance(protocol_interface_info_entry_t *cur)
02472 {
02473     if (!cur || !cur->rpl_domain) {
02474         return NULL;
02475     }
02476     struct rpl_instance *best_instance = NULL;
02477     ns_list_foreach(struct rpl_instance, instance, &cur->rpl_domain->instances) {
02478         best_instance = instance;
02479         // Select best grounded and lowest rank? But there should be only one really
02480     }
02481     return best_instance;
02482 }
02483 
02484 static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur)
02485 {
02486     mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur));
02487     if (!mac_neighbor) {
02488         return 0xffff;
02489     }
02490     ws_neighbor_class_entry_t *ws_neighbor =  ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_neighbor->index );
02491     if (!ws_neighbor) {
02492         return 0xffff;
02493     }
02494 
02495     uint16_t etx = etx_local_etx_read(cur->id, mac_neighbor->index );
02496     if (etx == 0) {
02497         etx = 0xffff;
02498     }
02499     if (etx > 0x800) {
02500         // Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0.
02501         etx = 0x800;
02502     }
02503     etx = etx >> 1;
02504 
02505     return ws_neighbor->routing_cost + etx;
02506 }
02507 
02508 static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur)
02509 {
02510     struct rpl_instance *rpl_instance = ws_get_rpl_instance(cur);
02511     if (!rpl_instance) {
02512         return 0xffff;
02513     }
02514     return rpl_control_current_rank(rpl_instance);
02515 }
02516 
02517 
02518 static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur)
02519 {
02520     struct rpl_instance *rpl_instance = ws_get_rpl_instance(cur);
02521     if (!rpl_instance) {
02522         return 0xffff;
02523     }
02524     struct rpl_dodag_info_t dodag_info;
02525     if (!rpl_control_read_dodag_info(rpl_instance, &dodag_info)) {
02526         return 0xffff;
02527     }
02528     return dodag_info.dag_min_hop_rank_inc;
02529 }
02530 
02531 static void ws_bootstrap_pan_advert(protocol_interface_info_entry_t *cur)
02532 {
02533     asynch_request_t async_req;
02534     memset(&async_req, 0, sizeof(asynch_request_t));
02535     async_req.message_type = WS_FT_PAN_ADVERT;
02536     //Request UTT Header, Pan information and US and Net name from payload
02537     async_req.wh_requested_ie_list.utt_ie = true;
02538     async_req.wp_requested_nested_ie_list.us_ie = true;
02539     async_req.wp_requested_nested_ie_list.pan_ie = true;
02540     async_req.wp_requested_nested_ie_list.net_name_ie = true;
02541 
02542     ws_set_asynch_channel_list(cur, &async_req);
02543     async_req.security.SecurityLevel = 0;
02544 
02545     if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
02546         // Border routers write the NW size
02547         cur->ws_info->pan_information.pan_size = ws_bbr_pan_size(cur);
02548         cur->ws_info->pan_information.routing_cost = 0;
02549     } else {
02550         // Nodes need to calculate routing cost
02551         // PAN size is saved from latest PAN advertisement
02552         cur->ws_info->pan_information.routing_cost = ws_bootstrap_routing_cost_calculate(cur);
02553     }
02554 
02555 
02556     ws_llc_asynch_request(cur, &async_req);
02557 }
02558 
02559 static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur)
02560 {
02561     asynch_request_t async_req;
02562     memset(&async_req, 0, sizeof(asynch_request_t));
02563     async_req.message_type = WS_FT_PAN_CONF;
02564     //Request UTT Header, Pan information and US and Net name from payload
02565     async_req.wh_requested_ie_list.utt_ie = true;
02566     async_req.wh_requested_ie_list.bt_ie = true;
02567     async_req.wp_requested_nested_ie_list.us_ie = true;
02568     async_req.wp_requested_nested_ie_list.bs_ie = true;
02569     async_req.wp_requested_nested_ie_list.pan_version_ie = true;
02570     async_req.wp_requested_nested_ie_list.gtkhash_ie = true;
02571     async_req.wp_requested_nested_ie_list.vp_ie = true;
02572 
02573     ws_set_asynch_channel_list(cur, &async_req);
02574 
02575     async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur);
02576     async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
02577     async_req.security.KeyIndex = mac_helper_default_key_index_get(cur);
02578     ws_llc_asynch_request(cur, &async_req);
02579 }
02580 
02581 static void ws_bootstrap_event_handler(arm_event_s *event)
02582 {
02583     ws_bootsrap_event_type_e event_type;
02584     event_type = (ws_bootsrap_event_type_e)event->event_type;
02585     protocol_interface_info_entry_t *cur;
02586     cur = protocol_stack_interface_info_get_by_bootstrap_id(event->receiver);
02587     if (!cur) {
02588         return;
02589     }
02590 
02591     switch (event_type) {
02592         case WS_INIT_EVENT:
02593             tr_debug("tasklet init");
02594             break;
02595         case WS_DISCOVERY_START:
02596             tr_info("Discovery start");
02597             // All trickle timers stopped to allow entry from any state
02598             cur->ws_info->trickle_pa_running = false;
02599             cur->ws_info->trickle_pc_running = false;
02600             cur->ws_info->trickle_pas_running = false;
02601             cur->ws_info->trickle_pcs_running = false;
02602 
02603             if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
02604                 tr_debug("Border router start network");
02605 
02606                 if (!ws_bbr_ready_to_start(cur)) {
02607                     // Wi-SUN not started yet we wait for Border router permission
02608                     ws_bootstrap_state_change(cur, ER_WAIT_RESTART);
02609                     cur->nwk_nd_re_scan_count = randLIB_get_random_in_range(40, 100);
02610                     return;
02611                 }
02612                 ws_pae_controller_auth_init(cur);
02613 
02614                 // Randomize fixed channels. Only used if channel plan is fixed.
02615                 cur->ws_info->fhss_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
02616                 cur->ws_info->fhss_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
02617                 cur->ws_info->network_pan_id = randLIB_get_random_in_range(0, 0xfffd);
02618                 cur->ws_info->pan_information.pan_size = 0;
02619                 cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff);
02620                 cur->ws_info->pan_information.routing_cost = 0;
02621                 cur->ws_info->pan_information.rpl_routing_method = true;
02622                 cur->ws_info->pan_information.use_parent_bs = true;
02623                 cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0;
02624 
02625                 uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
02626                 ws_llc_set_gtkhash(cur, gtkhash);
02627                 cur->ws_info->pan_version_timer = ws_common_version_lifetime_get(cur->ws_info->network_size_config);
02628 
02629                 // Set default parameters for FHSS when starting a discovery
02630                 ws_fhss_border_router_configure(cur);
02631                 ws_bootstrap_fhss_activate(cur);
02632                 ws_bootstrap_event_operation_start(cur);
02633 
02634                 uint8_t ll_addr[16];
02635                 addr_interface_get_ll_address(cur, ll_addr, 1);
02636 
02637                 //SET EAPOL authenticator EUI64
02638                 ws_pae_controller_border_router_addr_write(cur, cur->mac);
02639 
02640                 // Set EAPOL relay to port 10255 and authenticator relay to 10253 (and to own ll address)
02641                 ws_eapol_relay_start(cur, BR_EAPOL_RELAY_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
02642 
02643                 // Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address)
02644                 ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT);
02645 
02646                 // Set PAN ID and network name to controller
02647                 ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
02648 
02649                 // Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address)
02650                 ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
02651                 break;
02652             }
02653             ws_pae_controller_supp_init(cur);
02654 
02655             // Configure LLC for network discovery
02656             ws_bootstrap_network_discovery_configure(cur);
02657             ws_bootstrap_fhss_activate(cur);
02658             // Start network scan
02659             ws_bootstrap_start_discovery(cur);
02660             break;
02661 
02662         case WS_CONFIGURATION_START:
02663             tr_info("Configuration start");
02664             // Old configuration is considered invalid stopping all
02665             cur->ws_info->trickle_pa_running = false;
02666             cur->ws_info->trickle_pc_running = false;
02667             cur->ws_info->trickle_pas_running = false;
02668             cur->ws_info->trickle_pcs_running = false;
02669 
02670             // Build list of possible neighbours and learn first broadcast schedule
02671 
02672             ws_bootstrap_start_configuration_learn(cur);
02673             break;
02674         case WS_OPERATION_START:
02675             tr_info("operation start");
02676             // Advertisements stopped during the RPL scan
02677             cur->ws_info->trickle_pa_running = false;
02678             cur->ws_info->trickle_pc_running = false;
02679             cur->ws_info->trickle_pas_running = false;
02680             cur->ws_info->trickle_pcs_running = false;
02681             // Activate RPL
02682             // Activate IPv6 stack
02683             ws_bootstrap_ip_stack_activate(cur);
02684             ws_bootstrap_rpl_activate(cur);
02685             ws_bootstrap_network_start(cur);
02686             // Wait for RPL start
02687             if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
02688                 ws_bootstrap_event_routing_ready(cur);
02689             } else {
02690                 ws_bootstrap_rpl_scan_start(cur);
02691             }
02692             break;
02693         case WS_ROUTING_READY:
02694             tr_info("Routing ready");
02695             // stopped all to make sure we can enter here from any state
02696             cur->ws_info->trickle_pa_running = false;
02697             cur->ws_info->trickle_pc_running = false;
02698             cur->ws_info->trickle_pas_running = false;
02699             cur->ws_info->trickle_pcs_running = false;
02700 
02701             // Indicate PAE controller that bootstrap is ready
02702             ws_pae_controller_bootstrap_done(cur);
02703 
02704             ws_bootstrap_advertise_start(cur);
02705             ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE);
02706             break;
02707 
02708         default:
02709             tr_err("Invalid event received");
02710             break;
02711     }
02712 }
02713 
02714 /*
02715  * State machine
02716  *
02717  * */
02718 void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur)
02719 {
02720 
02721     parent_info_t *selected_parent_ptr;
02722 
02723     tr_debug("analyze network discovery result");
02724 
02725     selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur);
02726 
02727     if (!selected_parent_ptr) {
02728         // Next check will be after one trickle
02729         cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
02730         tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
02731         return;
02732     }
02733     tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id);
02734 
02735     // Add EAPOL neighbour
02736     cur->ws_info->network_pan_id = selected_parent_ptr->pan_id;
02737     cur->ws_info->pan_information = selected_parent_ptr->pan_information;
02738     cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration
02739 
02740     ws_bootstrap_fhss_activate(cur);
02741     llc_neighbour_req_t neighbor_info;
02742     if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) {
02743         return;
02744     }
02745 
02746     ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp);
02747     ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_us);
02748 
02749     ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth
02750     ws_bootstrap_event_authentication_start(cur);
02751     return;
02752 }
02753 
02754 void ws_bootstrap_configure_process(protocol_interface_info_entry_t *cur)
02755 {
02756 
02757     if (cur->ws_info->configuration_learned) {
02758         ws_bootstrap_network_configuration_learn(cur);
02759 
02760 
02761         ws_bootstrap_event_operation_start(cur);
02762 
02763 
02764         return;
02765     }
02766     return;
02767 }
02768 void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur)
02769 {
02770 
02771     if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) {
02772         // RPL routing is ready
02773         ws_bootstrap_event_routing_ready(cur);
02774     } else if (!rpl_control_have_dodag(cur->rpl_domain)) {
02775         // RPL not ready send DIS message if possible
02776         if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) {
02777             // TODO Multicast DIS should be sent only if no DIO heard for some time
02778             rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES);
02779         }
02780         // set timer for next DIS
02781         cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_TIMEOUT / 2, WS_RPL_DIS_TIMEOUT);
02782     }
02783     return;
02784 }
02785 
02786 /*
02787 
02788 static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur)
02789 {
02790     // Think about the state value
02791     if (cur->nwk_bootstrap_state == ER_SCAN) {
02792         return true;
02793     }
02794     return false;
02795 }
02796 
02797 */
02798 static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur)
02799 {
02800     if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) {
02801         return true;
02802     }
02803     return false;
02804 }
02805 
02806 static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur)
02807 {
02808     if (cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) {
02809         return true;
02810     }
02811     return false;
02812 }
02813 static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur)
02814 {
02815     // Think about the state value
02816     if (cur->nwk_bootstrap_state == ER_RPL_SCAN) {
02817         return true;
02818     }
02819     return false;
02820 }
02821 
02822 static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state)
02823 {
02824     cur->bootsrap_state_machine_cnt = 1;
02825     cur->nwk_bootstrap_state = nwk_bootstrap_state;
02826 }
02827 
02828 void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
02829 {
02830 
02831     switch (cur->nwk_bootstrap_state) {
02832         case ER_WAIT_RESTART:
02833             tr_debug("WS SM:Wait for startup");
02834             ws_bootstrap_event_discovery_start(cur);
02835             break;
02836         case ER_ACTIVE_SCAN:
02837             tr_debug("WS SM:Active Scan");
02838             ws_bootstrap_network_scan_process(cur);
02839             break;
02840         case ER_SCAN:
02841             tr_debug("WS SM:configuration Scan");
02842             ws_bootstrap_configure_process(cur);
02843             break;
02844         case ER_PANA_AUTH:
02845             tr_info("authentication start");
02846             // Advertisements stopped during the EAPOL
02847             cur->ws_info->trickle_pa_running = false;
02848             cur->ws_info->trickle_pc_running = false;
02849             cur->ws_info->trickle_pas_running = false;
02850             cur->ws_info->trickle_pcs_running = false;
02851 
02852             ws_bootstrap_start_authentication(cur);
02853             break;
02854         case ER_RPL_SCAN:
02855             tr_debug("WS SM:Wait RPL to contact DODAG root");
02856             ws_bootstrap_rpl_wait_process(cur);
02857             break;
02858         case ER_BOOTSRAP_DONE:
02859             tr_debug("WS SM:Bootstrap Done");
02860             // Bootstrap_done event to application
02861             nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur);
02862             break;
02863         default:
02864             tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state);
02865     }
02866 }
02867 
02868 void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks)
02869 {
02870     if (cur->ws_info->trickle_pas_running &&
02871             trickle_timer(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
02872         // send PAN advertisement solicit
02873         tr_info("Send PAN advertisement Solicit");
02874         ws_bootstrap_pan_advert_solicit(cur);
02875     }
02876     if (cur->ws_info->trickle_pcs_running &&
02877             trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
02878         // send PAN Configuration solicit
02879         if (cur->ws_info->pas_requests >= PCS_MAX) {
02880             // if MAX PCS sent restart discovery
02881 
02882             // Trickle is reseted when entering to discovery from state 3
02883             trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
02884             ws_bootstrap_event_discovery_start(cur);
02885             return;
02886         }
02887         tr_info("Send PAN configuration Solicit");
02888         cur->ws_info->pas_requests++;
02889         ws_bootstrap_pan_config_solicit(cur);
02890     }
02891     if (cur->ws_info->trickle_pa_running &&
02892             trickle_timer(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
02893         // send PAN advertisement
02894         tr_info("Send PAN advertisement");
02895         ws_bootstrap_pan_advert(cur);
02896     }
02897     if (cur->ws_info->trickle_pc_running &&
02898             trickle_timer(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
02899         // send PAN Configuration
02900         tr_info("Send PAN configuration");
02901         ws_bootstrap_pan_config(cur);
02902     }
02903 }
02904 
02905 
02906 void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds)
02907 {
02908     if (cur->ws_info->pan_version_timeout_timer) {
02909         // PAN version timer running
02910         if (cur->ws_info->pan_version_timeout_timer > seconds) {
02911             cur->ws_info->pan_version_timeout_timer -= seconds;
02912         } else {
02913             // Border router has timed out
02914             tr_warn("Border router has timed out");
02915             ws_bootstrap_event_discovery_start(cur);
02916         }
02917     }
02918 }
02919 
02920 void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor)
02921 {
02922     if (interface->ws_info) {
02923         llc_neighbour_req_t neighbor_info;
02924         neighbor_info.neighbor = neighbor;
02925         neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index );
02926         ws_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH);
02927         uint8_t link_local_address[16];
02928         ws_bootsrap_create_ll_address(link_local_address, neighbor->mac64 );
02929         dhcp_client_server_address_update(interface->id, NULL, link_local_address);
02930 
02931         ws_secondary_parent_update(interface);
02932     }
02933 }
02934 
02935 void ws_secondary_parent_update(protocol_interface_info_entry_t *interface)
02936 {
02937     if (interface->ws_info) {
02938         ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) {
02939             if (!addr_is_ipv6_link_local(address->address)) {
02940                 ws_address_registration_update(interface);
02941             }
02942         }
02943     }
02944 }
02945 
02946 void ws_bootstrap_etx_accelerate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh)
02947 {
02948     ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neigh->index );
02949     //Enable Faster ETX probing
02950     ws_neighbor->accelerated_etx_probe = true;
02951     //Move Neighbor to first to for accelerate Process
02952     mac_neighbor_table_t *table_class = mac_neighbor_info(interface);
02953     ns_list_remove(&table_class->neighbour_list , neigh);
02954     ns_list_add_to_start(&table_class->neighbour_list , neigh);
02955     //Try to Generate Active NUD Immediately
02956     if (!ws_neighbor_entry_nud_notify(neigh, interface)) {
02957         return;//Return if NUD active is full
02958     }
02959     table_class->active_nud_process ++;
02960     neigh->nud_active  = true;
02961     //Push NS to send
02962     ws_nud_active_timer(interface, 0);
02963 }
02964 
02965 #endif //HAVE_WS