/* * Copyright (c) 2015-2021, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * \file protocol_6lowpan_bootstrap.c * */ #include "nsconfig.h" #include "string.h" #include "ns_types.h" #include "ns_trace.h" #include "eventOS_scheduler.h" #include "nsdynmemLIB.h" #include "randLIB.h" #include "NWK_INTERFACE/Include/protocol.h" #include "NWK_INTERFACE/Include/protocol_timer.h" #include "Common_Protocols/icmpv6.h" #include "Common_Protocols/icmpv6_radv.h" #include "Common_Protocols/udp.h" #include "6LoWPAN/Bootstraps/network_lib.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h" #include "Service_Libs/blacklist/blacklist.h" #include "6LoWPAN/MAC/mac_helper.h" #include "mac_api.h" #include "net_pana_parameters_api.h" #ifdef HAVE_RPL #include "RPL/rpl_control.h" #endif #ifndef NO_MLE #include "MLE/mle.h" #include "MLE/mle_tlv.h" #endif #ifdef ECC #include "libX509_V3.h" #include "ecc.h" #endif #include "ccmLIB.h" #include "shalib.h" #include "net_nvm_api.h" #include "common_functions.h" #include "net_interface.h" #include "Security/TLS/tls_lib.h" #include "Security/Common/sec_lib.h" #include "Security/PANA/pana.h" #include "Security/PANA/pana_internal_api.h" #include "6LoWPAN/ND/nd_router_object.h" #include "BorderRouter/border_router.h" #include "6LoWPAN/Thread/thread_common.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "Service_Libs/etx/etx.h" #include "6LoWPAN/MAC/beacon_handler.h" #include "mac_api.h" #include "6LoWPAN/MAC/mac_data_poll.h" #include "libNET/src/net_load_balance_internal.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #include "6LoWPAN/NVM/nwk_nvm.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" /* Fixed-point randomisation limits for randlib_randomise_base() - RFC 3315 * says RAND is uniformly distributed between -0.1 and +0.1 */ #define LOWPAN_RAND_LOW 0x7333 // 1 - 0.1; minimum for "1+RAND" #define LOWPAN_RAND_HIGH 0x8CCD // 1 + 0.1; maximum for "1+RAND" #define TRACE_GROUP_LOWPAN_BOOT "6Bo" #define TRACE_GROUP "6Bo" #ifdef HAVE_6LOWPAN_ND #ifdef HAVE_RPL static int protocol_6lowpan_router_multicast_synch(protocol_interface_info_entry_t *cur); static void protocol_6lowpan_bootstrap_rpl_callback(rpl_event_t event, void *handle); #else #define protocol_6lowpan_router_multicast_synch(cur) (-1) #endif static void protocol_6lowpan_mle_purge_neighbors(struct protocol_interface_info_entry *cur_interface, uint8_t entry_count, uint8_t force_priority); static uint8_t protocol_6lowpan_mle_order_last_entries(int8_t interface_id, mac_neighbor_table_list_t *mac_neigh_table, uint8_t entry_count); static uint8_t protocol_6lowpan_mle_data_allocate(void); static bool mle_accept_request_cb(int8_t interface_id, uint16_t msgId, bool usedAllRetries); static void lowpan_comm_status_indication_cb(int8_t if_id, const mlme_comm_status_t *status); static void protocol_6lowpan_priority_neighbor_remove(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *cur); static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data); static bool lowpan_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data); static bool protocol_6lowpan_router_challenge(protocol_interface_info_entry_t *cur_interface, const uint8_t *mac64); static bool protocol_6lowpan_host_challenge(protocol_interface_info_entry_t *cur, const uint8_t *mac64); static void protocol_6lowpan_address_reg_ready(protocol_interface_info_entry_t *cur_interface); static void coordinator_black_list(protocol_interface_info_entry_t *cur); static mle_6lowpan_data_t *mle_6lowpan_data; #define MAX_MC_DIS_COUNT 3 static void lowpan_bootstrap_pan_control(protocol_interface_info_entry_t *cur, bool bootstrap_ready) { if (cur->mac_api) { mlme_start_t start_req; memset(&start_req, 0, sizeof(mlme_start_t)); start_req.BeaconOrder = 15; start_req.SuperframeOrder = 15; start_req.PANCoordinator = bootstrap_ready; start_req.LogicalChannel = cur->mac_parameters->mac_channel; start_req.PANId = cur->mac_parameters->pan_id; cur->mac_api->mlme_req(cur->mac_api, MLME_START, &start_req); net_load_balance_internal_state_activate(cur, bootstrap_ready); } } static uint8_t lowpan_mode_get_by_interface_ptr(protocol_interface_info_entry_t *cur) { uint8_t mle_mode = 0; if (!(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) { mle_mode |= MLE_RX_ON_IDLE; } if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { mle_mode |= (MLE_FFD_DEV); } return mle_mode; } uint8_t *mle_general_write_timeout(uint8_t *ptr, protocol_interface_info_entry_t *cur) { uint32_t timeout_value = 0; uint8_t mode = lowpan_mode_get_by_interface_ptr(cur); if (!mle_6lowpan_data) { return ptr; } if (!(mode & MLE_RX_ON_IDLE)) { timeout_value = mac_data_poll_host_timeout(cur); } if (timeout_value == 0) { timeout_value = mle_6lowpan_data->host_lifetime; } return mle_tlv_write_timeout(ptr, timeout_value); } static void protocol_6lowpan_priority_neighbor_remove(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *cur) { if (cur->link_role != PRIORITY_PARENT_NEIGHBOUR || !(cur_interface->lowpan_info & INTERFACE_NWK_ACTIVE) || cur_interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { return; } uint8_t mac64[8]; if (cur_interface->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { // Coordinating parent has been lost during bootstrap if (!cur_interface->global_address_available) { tr_debug("bootstrap coordinator down"); bootsrap_next_state_kick(ER_BOOTSTRAP_CONNECTION_DOWN, cur_interface); } } else { //Call Priority parent loose if (cur->mac16 != 0xffff) { memcpy(mac64, ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(cur->mac16, &mac64[6]); } else { memcpy(mac64, cur->mac64, 8); mac64[0] ^= 2; } if (nd_parent_loose_indcate(mac64, cur_interface) != 0) { //ND Router synch lost tr_debug("ND Router Synch Loose"); bootsrap_next_state_kick(ER_PARENT_SYNCH_LOST, cur_interface); } } } static bool protocol_6lowpan_challenge_callback(int8_t interface_id, uint16_t msgId, bool usedAllRetries) { protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id); if (!cur_interface) { return false; } uint8_t mac64[8]; uint8_t *ll64_ptr = mle_service_get_msg_destination_address_pointer(msgId); memcpy(mac64, ll64_ptr + 8, 8); mac64[0] ^= 2; mac_neighbor_table_entry_t *neig_info = mac_neighbor_table_address_discover(mac_neighbor_info(cur_interface), mac64, ADDR_802_15_4_LONG); if (!neig_info) { return false;//Why entry is removed before timeout?? } if (!neig_info->nud_active) { return false; } if (usedAllRetries) { //GET entry mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur_interface), neig_info); return false; } return true; } static bool protocol_6lowpan_host_challenge(protocol_interface_info_entry_t *cur, const uint8_t *mac64) { uint16_t bufId; mle_message_timeout_params_t timeout; uint8_t ll64[16]; //Challenge uint8_t security_level = mle_service_security_level_get(cur->id); tr_debug("Link REQUEST"); bufId = mle_service_msg_allocate(cur->id, 32, true, MLE_COMMAND_REQUEST); if (bufId == 0) { return false; } uint8_t *ptr = mle_service_get_data_pointer(bufId); ptr = mle_general_write_source_address(ptr, cur); ptr = mle_tlv_write_mode(ptr, lowpan_mode_get_by_interface_ptr(cur)); if (security_level) { ptr = mle_general_write_link_layer_framecounter(ptr, cur); } if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { ptr = mle_general_write_timeout(ptr, cur); } memcpy(ll64, ADDR_LINK_LOCAL_PREFIX, 8); memcpy(&ll64[8], mac64, 8); ll64[8] ^= 2; if (mle_service_update_length_by_ptr(bufId, ptr) != 0) { tr_debug("Buffer overflow at message write"); } timeout.retrans_max = 3; timeout.timeout_init = 2; timeout.timeout_max = 4; timeout.delay = MLE_NO_DELAY; //SET Destination address mle_service_set_msg_destination_address(bufId, ll64); //Set Callback mle_service_set_packet_callback(bufId, protocol_6lowpan_challenge_callback); mle_service_set_msg_timeout_parameters(bufId, &timeout); mle_service_send_message(bufId); return true; } static bool protocol_6lowpan_router_challenge(protocol_interface_info_entry_t *cur, const uint8_t *mac64) { uint16_t bufId; mle_message_timeout_params_t timeout; uint8_t ll64[16]; //Challenge uint8_t security_level = mle_service_security_level_get(cur->id); tr_debug("Link REQUEST"); bufId = mle_service_msg_allocate(cur->id, 32, true, MLE_COMMAND_REQUEST); if (bufId == 0) { return false; } uint8_t *ptr = mle_service_get_data_pointer(bufId); ptr = mle_general_write_source_address(ptr, cur); ptr = mle_tlv_write_mode(ptr, lowpan_mode_get_by_interface_ptr(cur)); if (security_level) { ptr = mle_general_write_link_layer_framecounter(ptr, cur); } memcpy(ll64, ADDR_LINK_LOCAL_PREFIX, 8); memcpy(&ll64[8], mac64, 8); ll64[8] ^= 2; if (mle_service_update_length_by_ptr(bufId, ptr) != 0) { tr_debug("Buffer overflow at message write"); } timeout.retrans_max = 2; timeout.timeout_init = 2; timeout.timeout_max = 4; timeout.delay = MLE_NO_DELAY; //SET Destination address mle_service_set_msg_destination_address(bufId, ll64); mle_service_set_msg_timeout_parameters(bufId, &timeout); mle_service_send_message(bufId); return true; } static uint8_t mle_advert_neigh_cnt(protocol_interface_info_entry_t *cur_interface, bool short_adr) { uint8_t advert_neigh_cnt; uint8_t neighb_max; uint8_t mle_neigh_cnt = mle_class_active_neigh_counter(cur_interface); if (short_adr == true) { neighb_max = 16; } else { neighb_max = 5; } if (mle_neigh_cnt > neighb_max) { advert_neigh_cnt = neighb_max; } else { advert_neigh_cnt = mle_neigh_cnt; } return (advert_neigh_cnt); } static uint8_t mle_link_quality_tlv_parse(uint8_t *mac64, uint16_t short_address, uint8_t *ptr, uint16_t data_length, uint8_t *iop_flags_ptr, uint8_t *link_idr_ptr) { uint8_t entry_size; if (data_length) { entry_size = (*ptr++ & 0x0f) + 3; data_length--; // Supports 2 and 8 bytes long MAC addresses if ((entry_size == 4) || (entry_size == 10)) { uint8_t own_addr_match = false; // Searches own address from link quality TLV while (data_length >= entry_size) { if (entry_size == 4) { if (common_read_16_bit(ptr + 2) == short_address) { own_addr_match = true; } } else { if (memcmp(ptr + 2, mac64, 8) == 0) { own_addr_match = true; } } // If own address is found returns success if (own_addr_match) { if (iop_flags_ptr) { *iop_flags_ptr = ptr[0]; } if (link_idr_ptr) { *link_idr_ptr = ptr[1]; } return 1; } ptr += entry_size; data_length -= entry_size; } } } return 0; } static bool neighbor_list_short_address_available(mac_neighbor_table_t *table_class) { ns_list_foreach(mac_neighbor_table_entry_t, cur_entry, &table_class->neighbour_list) { if (cur_entry->connected_device && cur_entry->mac16 == 0xffff) { return false; } } return true; } static uint8_t *mle_table_set_neighbours(protocol_interface_info_entry_t *cur, uint8_t *ptr) { uint8_t *len_ptr = 0; uint8_t neigh_count = 0; uint8_t neigh_count_max = 0; uint8_t *link_flags_ptr; mac_neighbor_table_entry_t *first_entry_ptr = NULL; mac_neighbor_table_list_t *neigh_list = &cur->mac_parameters->mac_neighbor_table->neighbour_list; *ptr++ = MLE_TYPE_LINK_QUALITY; len_ptr = ptr++; *len_ptr = 1; link_flags_ptr = ptr++; //*link_flags_ptr = 0x81; bool use_short_address_compression = neighbor_list_short_address_available(mac_neighbor_info(cur)); if (use_short_address_compression) { //complete, 2 bytes long link-layer address *link_flags_ptr = 0x81; } else { //complete, 8 bytes long link-layer address *link_flags_ptr = 0x87; } neigh_count_max = mle_advert_neigh_cnt(cur, use_short_address_compression); bool clean_entries = false; ns_list_foreach(mac_neighbor_table_entry_t, cur_entry, neigh_list) { if ((cur_entry->connected_device) && (cur_entry->advertisment == false)) { // If looping list, stops adding entries when at first sent entry again if (first_entry_ptr == cur_entry) { break; } else if (first_entry_ptr == NULL) { first_entry_ptr = cur_entry; } // Limits the number of entries that are sent if (++neigh_count > neigh_count_max) { *link_flags_ptr &= 0x7f; break; } if (cur_entry->link_role == PRIORITY_PARENT_NEIGHBOUR) { *ptr++ = MLE_NEIGHBOR_PRIORITY_LINK | MLE_NEIGHBOR_INCOMING_LINK | MLE_NEIGHBOR_OUTGOING_LINK; } else { *ptr++ = MLE_NEIGHBOR_INCOMING_LINK | MLE_NEIGHBOR_OUTGOING_LINK; } *ptr++ = etx_local_incoming_idr_read(cur->id, cur_entry->index) >> 3; if (use_short_address_compression) { ptr = common_write_16_bit(cur_entry->mac16, ptr); *len_ptr += 4; } else { memcpy(ptr, cur_entry->mac64, 8); ptr += 8; *len_ptr += 10; } // If end of the neighbor list, Mark a clean advertisment from the list if (cur_entry->link.next == 0) { clean_entries = true; } cur_entry->advertisment = true; } } if (clean_entries) { ns_list_foreach(mac_neighbor_table_entry_t, temp, neigh_list) { // Marks entries not sent temp->advertisment = false; } } return ptr; } #ifndef NO_MLE static int protocol_6lowpan_mle_neigh_advertise(protocol_interface_info_entry_t *cur) { /* How was this 40 calculated? Seems to be more than enough, at least. * MODE = 2+1, SRC_ADDR = 2+2, LINK = 2+1+4*neighbours, ROUTE = 2+MLE_ROUTE_MIN_OPTION_LEN+routers * Total = 10 + neighbours * 4 */ uint16_t neig_cache_size = 40 + 7; uint8_t short_temp[2] = {0xff, 0xff}; uint8_t *ptr; mle_message_timeout_params_t timeout; if (!cur) { return 0; } if (mac_neighbor_table_address_discover(mac_neighbor_info(cur), short_temp, ADDR_802_15_4_SHORT)) { neig_cache_size += mle_advert_neigh_cnt(cur, false) * 10; } else { neig_cache_size += mle_advert_neigh_cnt(cur, true) << 2; } uint16_t bufId = mle_service_msg_allocate(cur->id, neig_cache_size, false, MLE_COMMAND_ADVERTISEMENT); if (bufId == 0) { return -1; } timeout.retrans_max = 0; timeout.timeout_init = 0; timeout.timeout_max = 0; timeout.delay = MLE_NO_DELAY; tr_debug("Send MLE Advertisement"); mle_service_set_msg_destination_address(bufId, ADDR_LINK_LOCAL_ALL_ROUTERS); mle_service_set_msg_timeout_parameters(bufId, &timeout); ptr = mle_service_get_data_pointer(bufId); ptr = mle_general_write_source_address(ptr, cur); ptr = mle_tlv_write_mode(ptr, lowpan_mode_get_by_interface_ptr(cur)); ptr = mle_table_set_neighbours(cur, ptr); if (mle_service_update_length_by_ptr(bufId, ptr) != 0) { tr_debug("Buffer overflow at message write"); } return mle_service_send_message(bufId); } #endif static int mle_validate_6lowpan_link_request_message(uint8_t *ptr, uint16_t data_len, mle_tlv_info_t *tlv_info) { /** * MLE Request need to include always challenge * - MLE_TYPE_CHALLENGE */ if (mle_tlv_option_discover(ptr, data_len, MLE_TYPE_CHALLENGE, tlv_info) < 4) { // TLV not found or length is smaller than 4 return -1; } return 0; } static void mle_neigh_time_and_mode_update(mac_neighbor_table_entry_t *entry_temp, mle_message_t *mle_msg) { uint8_t *tlv_ptr = mle_msg->data_ptr; uint16_t tlv_length = mle_msg->data_length; mle_tlv_info_t mle_tlv_info; uint32_t timeout_tlv; if (!mle_6lowpan_data) { return; } protocol_interface_info_entry_t *cur = mle_msg->interface_ptr; if (mle_tlv_option_discover(tlv_ptr, tlv_length, MLE_TYPE_MODE, &mle_tlv_info) > 0) { uint8_t *t_ptr = mle_tlv_info.dataPtr; mle_mode_parse_to_mac_entry(entry_temp, *t_ptr); } if (mle_tlv_option_discover(tlv_ptr, tlv_length, MLE_TYPE_TIMEOUT, &mle_tlv_info) > 0) { timeout_tlv = common_read_32_bit(mle_tlv_info.dataPtr); } else { if (entry_temp->ffd_device) { timeout_tlv = mle_6lowpan_data->router_lifetime; } else { timeout_tlv = mle_6lowpan_data->host_lifetime; } } mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), entry_temp, timeout_tlv); } static void mle_neigh_entry_update_by_mle_tlv_list(int8_t interface_id, mac_neighbor_table_entry_t *entry_temp, uint8_t *tlv_ptr, uint16_t tlv_length, uint8_t *mac64, uint16_t short_address) { mle_tlv_info_t mle_tlv_info; if (tlv_length) { if (mle_tlv_option_discover(tlv_ptr, tlv_length, MLE_TYPE_SRC_ADDRESS, &mle_tlv_info) > 0) { entry_temp->mac16 = common_read_16_bit(mle_tlv_info.dataPtr); } if (mle_tlv_option_discover(tlv_ptr, tlv_length, MLE_TYPE_LINK_QUALITY, &mle_tlv_info) > 0) { uint8_t link_idr; uint8_t iop_flags; if (mle_link_quality_tlv_parse(mac64, short_address, mle_tlv_info.dataPtr, mle_tlv_info.tlvLen, &iop_flags, &link_idr)) { etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index, entry_temp->mac64); if ((iop_flags & MLE_NEIGHBOR_PRIORITY_LINK) == MLE_NEIGHBOR_PRIORITY_LINK) { entry_temp->link_role = CHILD_NEIGHBOUR; } else if (entry_temp->link_role == CHILD_NEIGHBOUR) { entry_temp->link_role = NORMAL_NEIGHBOUR; } } } } } //Generate link request static uint16_t mle_router_synch(protocol_interface_info_entry_t *cur, const uint8_t *destAddress, uint8_t delay, uint8_t incoming_idr, bool retrans, bool register_short) { mle_message_timeout_params_t timeout; uint16_t bufId = mle_service_msg_allocate(cur->id, 64, true, MLE_COMMAND_REQUEST); if (bufId == 0) { return 0; } uint8_t security_level = mle_service_security_level_get(cur->id); uint8_t *ptr = mle_service_get_data_pointer(bufId); if (register_short) { ptr = mle_tlv_write_source_address(ptr, cur->lowpan_desired_short_address); } else { ptr = mle_general_write_source_address(ptr, cur); } ptr = mle_tlv_write_mode(ptr, lowpan_mode_get_by_interface_ptr(cur)); if (security_level) { ptr = mle_general_write_link_layer_framecounter(ptr, cur); } if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { ptr = mle_general_write_timeout(ptr, cur); } if (destAddress && incoming_idr != 0) { uint8_t mac64[8]; memcpy(mac64, &destAddress[8], 8); mac64[0] ^= 2; ptr = mle_tlv_write_link_quality(ptr, incoming_idr, mac64, 0, false); } if (destAddress) { mle_service_set_msg_destination_address(bufId, destAddress); } else { mle_service_set_msg_destination_address(bufId, ADDR_LINK_LOCAL_ALL_ROUTERS); } if (retrans) { if (destAddress) { timeout.retrans_max = 3; timeout.timeout_init = 2; timeout.timeout_max = 4; } else { timeout.retrans_max = 2; timeout.timeout_init = 4; timeout.timeout_max = 4; } } else { timeout.retrans_max = 1; timeout.timeout_init = 2; timeout.timeout_max = 4; } timeout.delay = delay; if (mle_service_update_length_by_ptr(bufId, ptr) != 0) { tr_debug("Buffer overflow at message write"); } mle_service_set_msg_timeout_parameters(bufId, &timeout); mle_service_send_message(bufId); return bufId; } static int mle_router_accept_request_build(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, uint8_t *challenge, uint8_t chalLen, uint8_t type, uint8_t incoming_idr, uint8_t priority_flag) { uint16_t bufId; uint8_t mac64[8]; mle_message_timeout_params_t timeout; uint8_t security_level = mle_service_security_level_get(cur->id); if (type == MLE_COMMAND_ACCEPT) { bufId = mle_service_msg_allocate(cur->id, 64, false, type); timeout.retrans_max = 0; timeout.timeout_init = 0; timeout.timeout_max = 0; } else { bufId = mle_service_msg_allocate(cur->id, 64, true, type); timeout.retrans_max = 2; timeout.timeout_init = 2; timeout.timeout_max = 4; } if (bufId == 0) { return -1; } if (addr_is_ipv6_multicast(mle_msg->packet_dst_address)) { timeout.delay = MLE_STANDARD_RESPONSE_DELAY; } else { timeout.delay = MLE_NO_DELAY; } tr_debug("MLE Router Link Request response"); mle_service_set_msg_destination_address(bufId, mle_msg->packet_src_address); uint8_t *ptr = mle_service_get_data_pointer(bufId); ptr = mle_tlv_write_mode(ptr, lowpan_mode_get_by_interface_ptr(cur)); if (security_level) { ptr = mle_general_write_link_layer_framecounter(ptr, cur); } if (challenge && chalLen) { ptr = mle_tlv_write_response(ptr, challenge, chalLen); } memcpy(mac64, &mle_msg->packet_src_address[8], 8); mac64[0] ^= 2; ptr = mle_tlv_write_link_quality(ptr, incoming_idr, mac64, 0, priority_flag); ptr = mle_general_write_source_address(ptr, cur); if (mle_service_update_length_by_ptr(bufId, ptr) != 0) { tr_debug("Buffer overflow at message write"); } mle_service_set_msg_timeout_parameters(bufId, &timeout); if (type == MLE_COMMAND_ACCEPT) { mle_service_set_msg_token_bucket_priority(bufId); } else { mle_service_set_packet_callback(bufId, mle_accept_request_cb); } mle_service_send_message(bufId); return 0; } static void protocol_6lowpan_link_reject_handler(protocol_interface_info_entry_t *cur, uint8_t *ll64) { mac_neighbor_table_entry_t *mac_entry = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), ll64, false, NULL); tr_debug("MLE link reject"); if (mac_entry) { mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), mac_entry); } } static bool mle_child_update_cb(int8_t interface_id, uint16_t msgId, bool usedAllRetries) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return false; } if (mle_service_check_msg_response(msgId)) { return false; } if (usedAllRetries) { tr_debug("Link Update fail-->Reset bootstrap"); mac_data_poll_protocol_poll_mode_decrement(cur); bootsrap_next_state_kick(ER_BOOTSTRAP_CONNECTION_DOWN, cur); return false; } mac_data_poll_protocol_poll_mode_decrement(cur); return true; } int protocol_6lowpan_child_update(protocol_interface_info_entry_t *cur) { uint16_t bufId; uint8_t cordAddress[16]; if (protocol_6lowpan_interface_get_link_local_cordinator_address(cur, cordAddress) != 0) { return -1; } bufId = mle_router_synch(cur, cordAddress, MLE_NO_DELAY, 0, true, false); if (bufId == 0) { return -1; } return mle_service_set_packet_callback(bufId, mle_child_update_cb); } static bool mle_parent_link_req_cb(int8_t interface_id, uint16_t msgId, bool usedAllRetries) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return false; } if (mle_service_check_msg_response(msgId)) { if (cur->nwk_bootstrap_state == ER_MLE_LINK_REQ) { //Enter ND scan bootsrap_next_state_kick(ER_SCAN, cur); pan_coordinator_blacklist_free(&cur->pan_cordinator_black_list); } #ifdef HAVE_RPL else if (cur->nwk_bootstrap_state == ER_ROUTER_SYNCH) { //Trig RPL multicast dis cur->nwk_bootstrap_state = ER_RPL_MC; cur->bootsrap_state_machine_cnt = 55; } #endif else if (cur->nwk_bootstrap_state == ER_MLE_LINK_ADDRESS_SYNCH) { mac_data_poll_protocol_poll_mode_disable(cur); bootsrap_next_state_kick(ER_BOOTSRAP_DONE, cur); } else if (cur->nwk_bootstrap_state == ER_MLE_LINK_SHORT_SYNCH) { tr_debug("MAC16 address synch ready"); //SET Here 16-bit //SET MAC16 Address & LL16 mac_helper_mac16_address_set(cur, cur->lowpan_desired_short_address); protocol_6lowpan_set_ll16(cur, cur->lowpan_desired_short_address); protocol_6lowpan_address_reg_ready(cur); } return false; } if (usedAllRetries) { switch (cur->nwk_bootstrap_state) { case ER_MLE_LINK_REQ: case ER_MLE_LINK_ADDRESS_SYNCH: case ER_MLE_LINK_SHORT_SYNCH: if (cur->nwk_bootstrap_state == ER_MLE_LINK_REQ) { coordinator_black_list(cur); } tr_debug("Link synch fail %u", cur->nwk_bootstrap_state); bootsrap_next_state_kick(ER_BOOTSTRAP_CONNECTION_DOWN, cur); break; #ifdef HAVE_RPL case ER_ROUTER_SYNCH: bootsrap_next_state_kick(ER_RPL_MC, cur); break; #endif // HAVE_RPL default: break; } return false; } return true; } static bool mle_accept_request_cb(int8_t interface_id, uint16_t msgId, bool usedAllRetries) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return false; } if (mle_service_check_msg_response(msgId)) { return false; } if (usedAllRetries) { //If message has been sent by MLE service sends MLE reject to clear link if (mle_service_check_msg_sent(msgId)) { uint8_t *address_ptr = mle_service_get_msg_destination_address_pointer(msgId); tr_debug("No accept for Accept/Request"); mle_service_reject_message_build(cur->id, address_ptr, false); } return false; } return true; } int protocol_6lowpan_parent_link_req(protocol_interface_info_entry_t *cur) { uint16_t bufId; uint8_t cordAddress[16]; if (protocol_6lowpan_interface_get_link_local_cordinator_address(cur, cordAddress) != 0) { return -1; } bufId = mle_router_synch(cur, cordAddress, MLE_NO_DELAY, 0, true, false); if (bufId == 0) { tr_debug("No Buf"); return -1; } cur->nwk_bootstrap_state = ER_MLE_LINK_REQ; return mle_service_set_packet_callback(bufId, mle_parent_link_req_cb); } #ifdef HAVE_RPL static int protocol_6lowpan_router_multicast_synch(protocol_interface_info_entry_t *cur) { uint16_t bufId; bufId = mle_router_synch(cur, NULL, MLE_NO_DELAY, 0, true, false); if (bufId == 0) { return -1; } cur->nwk_bootstrap_state = ER_ROUTER_SYNCH; return mle_service_set_packet_callback(bufId, mle_parent_link_req_cb); } #endif static int protocol_6lowpan_parent_address_synch(protocol_interface_info_entry_t *cur, bool register_short) { uint16_t bufId; uint8_t cordAddress[16]; if (protocol_6lowpan_interface_get_link_local_cordinator_address(cur, cordAddress) != 0) { return -1; } bufId = mle_router_synch(cur, cordAddress, MLE_NO_DELAY, 0, true, register_short); if (bufId == 0) { return -1; } if (register_short) { cur->nwk_bootstrap_state = ER_MLE_LINK_SHORT_SYNCH; } else { cur->nwk_bootstrap_state = ER_MLE_LINK_ADDRESS_SYNCH; } return mle_service_set_packet_callback(bufId, mle_parent_link_req_cb); } static bool mle_new_link_req_cb(int8_t interface_id, uint16_t msgId, bool usedAllRetries) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return false; } uint8_t *address_ptr = mle_service_get_msg_destination_address_pointer(msgId); if (mle_service_check_msg_response(msgId)) { if (address_ptr && !addr_is_ipv6_multicast(address_ptr)) { // Remove from blacklist blacklist_update(address_ptr, true); } return false; } if (usedAllRetries) { if (address_ptr && !addr_is_ipv6_multicast(address_ptr)) { tr_warn("Sync fail to new router"); // Add to blacklist or update current entry blacklist_update(address_ptr, false); } return false; } return true; } int protocol_6lowpan_router_synch_to_new_router(protocol_interface_info_entry_t *cur, uint8_t *ll64, uint8_t incoming_idr, bool retrans) { uint16_t bufId; bufId = mle_router_synch(cur, ll64, MLE_STANDARD_RESPONSE_DELAY, incoming_idr, retrans, false); if (bufId == 0) { return -1; } return mle_service_set_packet_callback(bufId, mle_new_link_req_cb); } static uint8_t mle_calculate_idr(int8_t interface_id, mle_message_t *mle_msg, mac_neighbor_table_entry_t *entry_temp) { if (!entry_temp) { return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0, NULL) >> 3; } return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index, entry_temp->mac64) >> 3; } static bool mle_6lowpan_neighbor_limit_check(mle_message_t *mle_msg, uint8_t only_max_limit_chk) { uint16_t mle_neigh_cnt; bool link_quality = false; if (!mle_6lowpan_data || mle_6lowpan_data->nbr_of_neigh_max == 0) { return true; } mle_neigh_cnt = mle_class_active_neigh_counter(mle_msg->interface_ptr); // Neighbor max limit if (mle_neigh_cnt >= mle_6lowpan_data->nbr_of_neigh_max) { tr_debug("Number of neighbor max limit"); return false; } if (only_max_limit_chk) { return true; } if (mle_msg->message_type == MLE_COMMAND_REQUEST) { mle_tlv_info_t mle_tlv_info; if (mle_tlv_option_discover(mle_msg->data_ptr, mle_msg->data_length, MLE_TYPE_LINK_QUALITY, &mle_tlv_info) > 0) { link_quality = true; } } // Lower threshold reached, start to limit answering to multicast messages if (mle_neigh_cnt >= mle_6lowpan_data->nbr_of_neigh_lower_threshold) { // If multicast link request or link request was triggered from advertisement if (addr_is_ipv6_multicast(mle_msg->packet_dst_address) || link_quality == true) { // Upper threshold reached, no responses to multicasts anymore if (mle_neigh_cnt >= mle_6lowpan_data->nbr_of_neigh_upper_threshold) { return false; } uint16_t ignore_prob = randLIB_get_random_in_range(1, mle_6lowpan_data->nbr_of_neigh_upper_threshold - mle_6lowpan_data->nbr_of_neigh_lower_threshold); if (ignore_prob < (mle_neigh_cnt - mle_6lowpan_data->nbr_of_neigh_lower_threshold)) { return false; } } } return true; } void mle_6lowpan_message_handler(int8_t interface_id, mle_message_t *mle_msg, mle_security_header_t *security_headers) { uint8_t *t_ptr; uint8_t response_type; uint8_t mode = 0x0a; mle_tlv_info_t mle_tlv_info; mle_tlv_info_t mle_challenge; mac_neighbor_table_entry_t *entry_temp; uint8_t incoming_idr; uint16_t responseId, own_mac16; protocol_interface_info_entry_t *cur = mle_msg->interface_ptr; own_mac16 = mac_helper_mac16_address_get(cur); switch (mle_msg->message_type) { case MLE_COMMAND_REQUEST: tr_debug("Link REQ"); if (!cur->global_address_available) { return; } else if (mle_validate_6lowpan_link_request_message(mle_msg->data_ptr, mle_msg->data_length, &mle_challenge) != 0) { return; } entry_temp = NULL; //If link request frame counter is invalid do not update neighbor entry and use three way handshake if (security_headers->invalid_frame_counter) { //Limit rate for triggering link requests if (!mle_6lowpan_data->link_req_token_bucket) { return; } mle_6lowpan_data->link_req_token_bucket--; } else { //Update only old information based on link request entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL); if (entry_temp) { mle_neigh_time_and_mode_update(entry_temp, mle_msg); mle_neigh_entry_update_by_mle_tlv_list(interface_id, entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur->mac, own_mac16); mle_neigh_entry_frame_counter_update(entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur, security_headers->KeyIndex); } else { if (!mle_6lowpan_neighbor_limit_check(mle_msg, false)) { return; } } } incoming_idr = mle_calculate_idr(interface_id, mle_msg, entry_temp); if (entry_temp && entry_temp->connected_device) { response_type = MLE_COMMAND_ACCEPT; } else { response_type = MLE_COMMAND_ACCEPT_AND_REQUEST; } mle_router_accept_request_build(cur, mle_msg, mle_challenge.dataPtr, mle_challenge.tlvLen, response_type, incoming_idr, false); break; case MLE_COMMAND_ACCEPT_AND_REQUEST: case MLE_COMMAND_ACCEPT: if (mle_msg->message_type == MLE_COMMAND_ACCEPT_AND_REQUEST) { if (mle_validate_6lowpan_link_request_message(mle_msg->data_ptr, mle_msg->data_length, &mle_challenge) != 0) { return; } } //Validate Response First responseId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (responseId == 0) { return; } tr_debug("Accept & Request"); entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL); if (!entry_temp) { // If there is space for neighbors try to allocate new entry if (mle_6lowpan_neighbor_limit_check(mle_msg, true)) { entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, true, NULL); } } if (!entry_temp) { tr_debug("Reject by no space"); mle_service_reject_message_build(cur->id, mle_msg->packet_src_address, false); return; } //Init mle security counters //Response state set now timeout know positive state mle_service_set_msg_response_true(responseId); entry_temp->connected_device = 1; mac_data_poll_protocol_poll_mode_decrement(cur); //Read Source address and Challenge mle_neigh_time_and_mode_update(entry_temp, mle_msg); if (mle_msg->message_type == MLE_COMMAND_ACCEPT_AND_REQUEST) { // If no global address set priority (bootstrap ongoing) if (!cur->global_address_available) { entry_temp->link_role = PRIORITY_PARENT_NEIGHBOUR; } mle_neigh_entry_update_by_mle_tlv_list(cur->id, entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur->mac, own_mac16); incoming_idr = mle_calculate_idr(cur->id, mle_msg, entry_temp); uint8_t priority = (entry_temp->link_role == PRIORITY_PARENT_NEIGHBOUR); mle_router_accept_request_build(cur, mle_msg, mle_challenge.dataPtr, mle_challenge.tlvLen, MLE_COMMAND_ACCEPT, incoming_idr, priority); } else { mle_neigh_entry_update_by_mle_tlv_list(cur->id, entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur->mac, own_mac16); incoming_idr = mle_calculate_idr(cur->id, mle_msg, entry_temp); } mle_neigh_entry_frame_counter_update(entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur, security_headers->KeyIndex); // If MLE frame counter was invalid update its value since three way handshake is complete if (security_headers->invalid_frame_counter) { mle_service_frame_counter_entry_add(interface_id, entry_temp->index, security_headers->frameCounter); } break; case MLE_COMMAND_REJECT: if (security_headers->invalid_frame_counter) { return; } protocol_6lowpan_link_reject_handler(cur, mle_msg->packet_src_address); break; case MLE_COMMAND_ADVERTISEMENT: tr_info("Received MLE Advertisement from %s", trace_ipv6(mle_msg->packet_src_address)); if (!cur->global_address_available || security_headers->invalid_frame_counter) { tr_error("MLE adv: Invalid frame counter: %s", security_headers->invalid_frame_counter ? "true" : "false"); return; } else { uint8_t drop_advertisment = 0; if (mle_tlv_option_discover(mle_msg->data_ptr, mle_msg->data_length, MLE_TYPE_MODE, &mle_tlv_info) > 0) { t_ptr = mle_tlv_info.dataPtr; mode = *t_ptr; } entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL); if (!entry_temp) { if ((mode & MLE_DEV_MASK) == MLE_FFD_DEV) { // If there is space for neighbors synchronizes to new router if (mle_6lowpan_neighbor_limit_check(mle_msg, false)) { // Checks blacklist if (blacklist_reject(mle_msg->packet_src_address)) { return; } incoming_idr = mle_calculate_idr(interface_id, mle_msg, NULL); protocol_6lowpan_router_synch_to_new_router(cur, mle_msg->packet_src_address, 0, false); } } tr_error("MLE adv: No MLE entry"); return; } //Verify Own Address drop_advertisment = 1; //Disvover own address only when we are aloocated address if (mle_tlv_option_discover(mle_msg->data_ptr, mle_msg->data_length, MLE_TYPE_LINK_QUALITY, &mle_tlv_info) > 0) { uint8_t link_flags; if (mle_tlv_info.tlvLen > 0) { link_flags = *(mle_tlv_info.dataPtr); if (mle_link_quality_tlv_parse(cur->mac, mac_helper_mac16_address_get(cur), mle_tlv_info.dataPtr, mle_tlv_info.tlvLen, NULL, NULL)) { drop_advertisment = 0; } if (drop_advertisment) { if (link_flags & 0x80) { //Total Entry at messgae //Possible remove if ((mode & MLE_DEV_MASK) == MLE_RFD_DEV) { //Remove Entry mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), entry_temp); tr_error("MLE adv: Own address not found"); return; } } } } } //UPDATE mle_neigh_entry_update_by_mle_tlv_list(cur->id, entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur->mac, own_mac16); mle_neigh_entry_frame_counter_update(entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur, security_headers->KeyIndex); if (entry_temp->connected_device) { mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), entry_temp, entry_temp->link_lifetime); } } break; default: break; } } int8_t arm_6lowpan_mle_service_ready_for_security_init(protocol_interface_info_entry_t *cur) { //Verify MLE Service if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) { //validate MLE service if (!mle_service_interface_registeration_validate(cur->id)) { //Register if (mle_service_interface_register(cur->id, cur, mle_6lowpan_message_handler, cur->mac, 8) != 0) { tr_error("Mle Service init Fail"); return -1; } if (mle_6lowpan_data) { if (mle_service_interface_token_bucket_settings_set(cur->id, mle_6lowpan_data->token_bucket_size, mle_6lowpan_data->token_bucket_rate, mle_6lowpan_data->token_bucket_count) < 0) { return -1; } mle_service_set_frame_counter_check(true); mle_service_set_accept_invalid_frame_counter(true); } } } return 0; } static uint8_t protocol_6lowpan_mle_data_allocate(void) { if (mle_6lowpan_data) { return 0; } mle_6lowpan_data = ns_dyn_mem_alloc(sizeof(mle_6lowpan_data_t)); if (!mle_6lowpan_data) { return 0; } mle_6lowpan_data->router_lifetime = MLE_ROUTER_DEFAULT_LIFETIME; mle_6lowpan_data->host_lifetime = MLE_ROUTER_HOST_LIFETIME; mle_6lowpan_data->nbr_of_neigh_lower_threshold = MLE_NBR_OF_NEIGHBOR_MAX_LIMIT; mle_6lowpan_data->nbr_of_neigh_upper_threshold = MLE_NBR_OF_NEIGHBOR_LOWER_THRESHOLD; mle_6lowpan_data->nbr_of_neigh_max = MLE_NBR_OF_NEIGHBOR_UPPER_THRESHOLD; mle_6lowpan_data->token_bucket_size = MLE_TOKEN_BUCKET_SIZE; mle_6lowpan_data->token_bucket_rate = MLE_TOKEN_BUCKET_RATE; mle_6lowpan_data->token_bucket_count = MLE_TOKEN_BUCKET_COUNT; mle_6lowpan_data->link_req_token_bucket = MLE_LINK_REQ_TOKEN_BUCKET_SIZE; return 0; } mle_6lowpan_data_t *protocol_6lowpan_mle_data_get(void) { return mle_6lowpan_data; } static void protocol_6lowpan_mle_purge_neighbors(struct protocol_interface_info_entry *cur_interface, uint8_t entry_count, uint8_t force_priority) { uint8_t count = 0; uint8_t ll64[16]; if (!cur_interface) { return; } mac_neighbor_table_list_t *mac_table_list = &cur_interface->mac_parameters->mac_neighbor_table->neighbour_list; entry_count = protocol_6lowpan_mle_order_last_entries(cur_interface->id, mac_table_list, entry_count); ns_list_foreach_reverse_safe(mac_neighbor_table_entry_t, entry, mac_table_list) { if (++count > entry_count) { break; } if (!force_priority) { if (entry->link_role == PRIORITY_PARENT_NEIGHBOUR || entry->link_role == CHILD_NEIGHBOUR) { break; } } memcpy(ll64, ADDR_LINK_LOCAL_PREFIX, 8); memcpy(&ll64[8], entry->mac64, 8); ll64[8] ^= 2; tr_debug("MLE purge"); // Sends REJECT mle_service_reject_message_build(cur_interface->id, ll64, false); mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur_interface), entry); // Adds purged neighbor to blacklist so that it is not added right away back from advertisement blacklist_update(ll64, false); } } static uint8_t protocol_6lowpan_mle_order_last_entries(int8_t interface_id, mac_neighbor_table_list_t *mac_neigh_table, uint8_t entry_count) { mac_neighbor_table_entry_t *last; mac_neighbor_table_entry_t *first_ordered = NULL; etx_storage_t *etx_last, *etx_cur; uint8_t count = 0; do { last = NULL; ns_list_foreach(mac_neighbor_table_entry_t, entry, mac_neigh_table) { if (entry == first_ordered) { break; } if (last == NULL) { last = entry; continue; } if (entry->link_role > last->link_role) { //Bigger link role is allways better continue; } else if (entry->link_role == last->link_role) { // Compare ETX when Link role is same etx_cur = etx_storage_entry_get(interface_id, entry->index); etx_last = etx_storage_entry_get(interface_id, last->index); if (etx_cur && etx_last && etx_cur->etx <= etx_last->etx) { continue; } } last = entry; } // Sets last to end of list if (last) { ns_list_remove(mac_neigh_table, last); if (first_ordered) { ns_list_add_before(mac_neigh_table, first_ordered, last); } else { ns_list_add_to_end(mac_neigh_table, last); } first_ordered = last; count++; if (count == entry_count) { break; } // If no lasts anymore then exits } else { break; } } while (true); return count; } static int8_t arm_6lowpan_bootstrap_down(protocol_interface_info_entry_t *cur) { if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { return -1; } mac_data_poll_disable(cur); /* Save security counter values to RAM and NVM */ if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } cur->if_lowpan_security_params->mle_security_frame_counter = mle_service_security_get_frame_counter(cur->id); mle_service_interface_receiver_handler_update(cur->id, mle_6lowpan_message_handler); // Reset MAC for safe upper layer memory free protocol_mac_reset(cur); return nwk_6lowpan_down(cur); } #ifdef HAVE_6LOWPAN_ND static void lowpan_mle_receive_security_bypass_cb(int8_t interface_id, mle_message_t *mle_msg) { (void) interface_id; #ifdef PANA protocol_interface_info_entry_t *interface = mle_msg->interface_ptr; //Accept Only Link Reject if (mle_msg->message_type == MLE_COMMAND_REJECT) { if ((interface->lowpan_info & (INTERFACE_NWK_BOOTSRAP_ACTIVE | INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION)) != (INTERFACE_NWK_BOOTSRAP_ACTIVE | INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION)) { return; } if (protocol_6lowpan_interface_compare_cordinator_netid(interface, mle_msg->packet_src_address + 8) != 0) { return; } if (interface->nwk_bootstrap_state != ER_PANA_AUTH) { return; } //Stop Pana and call ECC tr_debug("MLE Link reject from cordinator"); pana_reset_client_session(); bootsrap_next_state_kick(ER_PANA_AUTH_ERROR, interface); } #else (void)mle_msg; #endif } void arm_6lowpan_security_init_ifup(protocol_interface_info_entry_t *cur) { if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) { mle_service_security_init(cur->id, cur->if_lowpan_security_params->security_level, cur->if_lowpan_security_params->mle_security_frame_counter, NULL, protocol_6lowpan_mle_service_security_notify_cb); switch (cur->if_lowpan_security_params->nwk_security_mode) { case NET_SEC_MODE_PSK_LINK_SECURITY: mle_service_security_set_security_key(cur->id, cur->if_lowpan_security_params->psk_key_info.security_key, cur->if_lowpan_security_params->psk_key_info.key_id, true); mle_service_security_set_frame_counter(cur->id, cur->if_lowpan_security_params->mle_security_frame_counter); break; case NET_SEC_MODE_PANA_LINK_SECURITY: mle_service_interface_receiver_bypass_handler_update(cur->id, lowpan_mle_receive_security_bypass_cb); break; default: break; } } cur->mac_parameters->mac_key_id_mode = MAC_KEY_ID_MODE_IDX; cur->mac_parameters->mac_configured_sec_level = cur->if_lowpan_security_params->security_level; switch (cur->if_lowpan_security_params->nwk_security_mode) { case NET_SEC_MODE_PANA_LINK_SECURITY: cur->lowpan_info |= (INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION); break; case NET_SEC_MODE_PSK_LINK_SECURITY: mac_helper_security_default_key_set(cur, cur->if_lowpan_security_params->psk_key_info.security_key, cur->if_lowpan_security_params->psk_key_info.key_id, MAC_KEY_ID_MODE_IDX); /* fall through */ default: cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION; break; } } #endif static int8_t arm_6lowpan_bootstrap_up(protocol_interface_info_entry_t *cur) { int8_t ret_val = -1; if ((cur->configure_flags & INTERFACE_SETUP_MASK) != INTERFACE_SETUP_READY) { tr_debug("Interface not yet fully configured"); ret_val = -5; } else { //Verify MLE Service if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) { //validate MLE service if (!mle_service_interface_registeration_validate(cur->id)) { //Register if (mle_service_interface_register(cur->id, cur, mle_6lowpan_message_handler, cur->mac, 8) != 0) { tr_error("Mle Service init Fail"); return -1; } } if (mle_6lowpan_data) { if (mle_service_interface_token_bucket_settings_set(cur->id, mle_6lowpan_data->token_bucket_size, mle_6lowpan_data->token_bucket_rate, mle_6lowpan_data->token_bucket_count) < 0) { tr_error("Mle Service tokens set Fail"); return -1; } mle_service_set_frame_counter_check(true); mle_service_set_accept_invalid_frame_counter(true); } } arm_6lowpan_security_init_ifup(cur); //SET 6lowpan default here mac_helper_mac_mlme_max_retry_set(cur->id, LOWPAN_MAX_FRAME_RETRIES); addr_interface_set_ll64(cur, NULL); if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) { cur->lowpan_info |= INTERFACE_NWK_ROUTER_DEVICE; //rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, true); icmpv6_radv_enable(cur); } ret_val = nwk_6lowpan_up(cur); } return ret_val; } #endif void arm_6lowpan_bootstrap_init(protocol_interface_info_entry_t *cur) { //Init 6lowpan Bootsrap icmp_nd_routers_init(); cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE; cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY; bootsrap_next_state_kick(ER_SCAN, cur); mac_helper_mac16_address_set(cur, 0xffff); } #ifdef HAVE_6LOWPAN_ND static void arm_6lowpan_bootstrap_functions_set(protocol_interface_info_entry_t *cur) { cur->if_up = arm_6lowpan_bootstrap_up; cur->if_down = arm_6lowpan_bootstrap_down; } static uint8_t protocol_6lowpan_analyze_beacon_payload(uint8_t *ptr, uint8_t len, protocol_interface_info_entry_t *cur) { (void)len; nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params); if (*ptr == filter->beacon_protocol_id_filter || filter->beacon_protocol_id_filter == 0xff) { ptr++; if (filter->nwk_active_scan_level == 2) { if ((*ptr & 1)) { if (filter->beacon_nwk_id_filter) { ptr++; if (memcmp(filter->beacon_nwk_id_filter, ptr, 16)) { tr_debug("NWK ID filter"); return 0; } } return 1; } } else { return 1; } } return 0; } int8_t arm_network_processor_up(protocol_interface_info_entry_t *cur) { int8_t ret_val = -1; if ((cur->configure_flags & INTERFACE_SETUP_NETWORK_DRIVER_MASK) != INTERFACE_SETUP_NETWORK_DRIVER_READY) { tr_debug("Interface not yet fully configured\n"); ret_val = -5; } else { protocol_6lowpan_register_handlers(cur); mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, true); mac_helper_default_security_level_set(cur, SEC_NONE); if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_SNIFFER) { mac_helper_pib_boolean_set(cur, macAssociationPermit, false); mac_helper_pib_boolean_set(cur, macPromiscuousMode, true); lowpan_bootstrap_pan_control(cur, false); } else if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_ACCESPOINT) { // Updates beacon beacon_join_priority_update(cur->id); mac_helper_pib_boolean_set(cur, macAssociationPermit, true); net_load_balance_internal_state_activate(cur, true); } cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; cur->interface_mode = INTERFACE_UP; cur->nwk_mode = ARM_NWK_RAW_PHY_MODE; cur->lowpan_info |= (INTERFACE_NWK_ACTIVE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY); cur->bootsrap_state_machine_cnt = 0; nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); ret_val = 0; } return ret_val; } static void arm_6lowpan_security_key_update_cb(protocol_interface_info_entry_t *cur, const mlme_security_t *security_params) { if (cur->mac_parameters->mac_next_key_index && (security_params->KeyIndex == cur->mac_parameters->mac_next_key_index)) { tr_debug("Trig Next Key"); mac_helper_security_key_swap_next_to_default(cur); mle_service_security_key_trig(cur->id, security_params->KeyIndex); if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } } } static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) { protocol_interface_info_entry_t *cur_interface = user_data; lowpan_adaptation_neigh_remove_free_tx_tables(cur_interface, entry_ptr); // Sleepy host if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { mac_data_poll_protocol_poll_mode_decrement(cur_interface); } protocol_6lowpan_priority_neighbor_remove(cur_interface, entry_ptr); if (entry_ptr->ffd_device) { protocol_6lowpan_release_short_link_address_from_neighcache(cur_interface, entry_ptr->mac16); protocol_6lowpan_release_long_link_address_from_neighcache(cur_interface, entry_ptr->mac64); } mac_helper_devicetable_remove(cur_interface->mac_api, entry_ptr->index, entry_ptr->mac64); //Removes ETX neighbor etx_neighbor_remove(cur_interface->id, entry_ptr->index, entry_ptr->mac64); //Remove MLE frame counter info mle_service_frame_counter_entry_delete(cur_interface->id, entry_ptr->index); } static bool lowpan_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) { // Sleepy host protocol_interface_info_entry_t *cur_interface = user_data; if (cur_interface->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { //Trig middle way challenge if Broadcast message have been missed if (!entry_ptr->ffd_device) { return false; //End device must do this } if (entry_ptr->lifetime > (entry_ptr->link_lifetime / 2)) { return false; //Trig only when midway is overed } return protocol_6lowpan_router_challenge(cur_interface, entry_ptr->mac64); } if (entry_ptr->link_role != PRIORITY_PARENT_NEIGHBOUR) { return false; //Do not never challenge than priority parent } if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { return false; //Sleepy end device should not never challenge } if (entry_ptr->lifetime > MLE_TABLE_CHALLENGE_TIMER) { return false; } return protocol_6lowpan_host_challenge(cur_interface, entry_ptr->mac64); } int8_t arm_6lowpan_bootstarp_bootstrap_set(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode, net_6lowpan_mode_extension_e net_6lowpan_mode_extension) { int8_t ret_val = -1; bool enable_mle_protocol = true; protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } arm_6lowpan_bootstrap_functions_set(cur); cur->mac_parameters->beacon_ind = protocol_6lowpan_analyze_beacon_payload; mac_beacon_link_beacon_join_priority_tx_callback_set(cur->id, protocol_6lowpan_beacon_join_priority_tx); mac_beacon_link_beacon_compare_rx_callback_set(cur->id, protocol_6lowpan_beacon_compare_rx); if (net_6lowpan_mode_extension == NET_6LOWPAN_ND_WITHOUT_MLE) { enable_mle_protocol = false; } cur->mac_security_key_usage_update_cb = arm_6lowpan_security_key_update_cb; //Allocate MLE class here //Deallocate old here mac_neighbor_table_delete(mac_neighbor_info(cur)); mac_description_storage_size_t buffer; //Read MAC device table sizes if (cur->mac_api->mac_storage_sizes_get(cur->mac_api, &buffer) != 0) { return -1; } mac_neighbor_info(cur) = mac_neighbor_table_create(buffer.device_decription_table_size, lowpan_neighbor_entry_remove_notify , lowpan_neighbor_entry_nud_notify, cur); if (!mac_neighbor_info(cur)) { return -1; } if (enable_mle_protocol) { if (mle_service_frame_counter_table_allocate(interface_id, buffer.device_decription_table_size)) { return -1; } if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) { return -1; } lowpan_adaptation_interface_etx_update_enable(cur->id); } mle_service_interface_unregister(cur->id); if (bootstrap_mode == NET_6LOWPAN_NETWORK_DRIVER || bootstrap_mode == NET_6LOWPAN_SNIFFER) { enable_mle_protocol = false; cur->if_up = arm_network_processor_up; if (bootstrap_mode == NET_6LOWPAN_NETWORK_DRIVER) { cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_ACCESPOINT; cur->mac_parameters->beacon_ind = NULL; //Drop beacons } else { cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_SNIFFER; } cur->lowpan_info &= ~INTERFACE_NWK_ROUTER_DEVICE; cur->lowpan_info |= INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE; arm_nwk_6lowpan_borderrouter_data_free(cur); ret_val = 0; goto bootstrap_finish_check; } else { if (enable_mle_protocol) { #ifdef NO_MLE return -2; #else cur->comm_status_ind_cb = lowpan_comm_status_indication_cb; if (mle_service_interface_register(cur->id, cur, mle_6lowpan_message_handler, cur->mac, 8) != 0) { tr_error("Mle Service init Fail"); return -1; } if (protocol_6lowpan_mle_data_allocate() != 0) { tr_error("MLE data allocate Fail"); return -1; } if (blacklist_init() != 0) { tr_error("Blacklist init Fail"); return -1; } if (mle_6lowpan_data) { if (mle_service_interface_token_bucket_settings_set(cur->id, mle_6lowpan_data->token_bucket_size, mle_6lowpan_data->token_bucket_rate, mle_6lowpan_data->token_bucket_count) < 0) { tr_error("Mle Service tokens set Fail"); return -1; } mle_service_set_frame_counter_check(true); mle_service_set_accept_invalid_frame_counter(true); } #endif } arm_6lowpan_bootstrap_functions_set(cur); cur->configure_flags &= ~INTERFACE_BOOTSTRAP_DEFINED; switch (bootstrap_mode) { case NET_6LOWPAN_HOST: protocol_6lowpan_host_init(cur, false); ret_val = 0; break; case NET_6LOWPAN_SLEEPY_HOST: protocol_6lowpan_host_init(cur, true); ret_val = 0; break; case NET_6LOWPAN_ROUTER: protocol_6lowpan_router_init(cur); ret_val = 0; break; case NET_6LOWPAN_BORDER_ROUTER: ret_val = arm_nwk_6lowpan_borderrouter_init(cur); cur->mac_parameters->beacon_ind = NULL; //Drop beacons break; default: break; } } bootstrap_finish_check: if (ret_val == 0) { /** * Do Thread dealloc */ thread_info_deallocate(cur); //ADD RPL Support if supported and device is router #ifdef HAVE_RPL /** * ADD RPL Flag If device is router */ if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { //rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, true); //rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, NULL, NULL, cur); } #endif cur->configure_flags |= INTERFACE_BOOTSTRAP_DEFINED; if (enable_mle_protocol) { cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_MLE; } else { cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_MLE; } } return ret_val; } static void protocol_6lowpan_bootstrap_icmp_rs_msg_tx(protocol_interface_info_entry_t *cur) { buffer_t *buf = icmpv6_build_rs(cur, NULL); protocol_push(buf); } void nwk_6lowpan_router_scan_state(protocol_interface_info_entry_t *cur) { cur->nwk_rpl_scan_counter = 0; if (cur->nwk_nd_re_scan_count == 0) { if (cur->border_router_setup) { //Activate RS arm_border_router_ready(cur); } else { tr_warn("No ND Router"); nwk_bootsrap_state_update(ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL, cur); } } else { //Verify is ND Object allocated already if (!cur->border_router_setup && nd_object_active()) { tr_debug("Wait response from ND"); } else { tr_debug("RS*"); protocol_6lowpan_bootstrap_icmp_rs_msg_tx(cur); cur->nwk_nd_re_scan_count--; if (cur->border_router_setup) { cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(25, 50); } else { if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) { cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(25, 40); } else { cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(60, 70); } } } } } void nwk_6lowpan_bootstrap_ready(protocol_interface_info_entry_t *cur) { if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) { uint8_t bootsrap_ready = 0; if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION) { if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { if (pana_ping_notify_msg_tx(cur->mac_parameters->pan_id) == 0) { tr_warn("PING TX fail"); } else { bootsrap_ready = 1; } } else { if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) { #ifndef NO_MLE tr_debug("MLE Parent Advertisment"); if (protocol_6lowpan_mle_neigh_advertise(cur) == 0) { bootsrap_ready = 1; } else { tr_warn("MLE Host Parent Advert TX fail"); } #endif } else { bootsrap_ready = 1; } } } else { bootsrap_ready = 1; } if (bootsrap_ready) { if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { // Updates beacon beacon_join_priority_update(cur->id); lowpan_bootstrap_pan_control(cur, true); } nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); } else { cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; cur->bootsrap_state_machine_cnt = 2; } } } void protocol_6lowpan_link_advertise_handle(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint16_t tick) { if ((cur_interface->lowpan_info & (INTERFACE_NWK_BOOTSRAP_MLE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) == (INTERFACE_NWK_BOOTSRAP_MLE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) { #ifndef NO_MLE if (cur->mle_advert_timer) { if (cur->mle_advert_timer > tick) { cur->mle_advert_timer -= tick; } else { if (protocol_6lowpan_mle_neigh_advertise(cur_interface) == 0) { if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { cur->mle_advert_timer = 0; } else { cur->mle_advert_timer = 155; if (mle_6lowpan_data) { uint16_t period = mle_6lowpan_data->router_lifetime / 4; if (period > 640) { period = 640; } period *= 10; //seconds ticks --> 100ms ticks //set 0.9 - 1.1 * period cur->mle_advert_timer = randLIB_randomise_base(period, LOWPAN_RAND_LOW, LOWPAN_RAND_HIGH); } } } else { cur->mle_advert_timer = 2; } if (cur->mle_purge_timer) { cur->mle_purge_timer -= 1; } else { if (mle_6lowpan_data && mle_6lowpan_data->nbr_of_neigh_max != 0) { uint16_t mle_neigh_cnt = mle_class_active_neigh_counter(cur_interface); if (mle_neigh_cnt > (mle_6lowpan_data->nbr_of_neigh_max - MLE_NEIGHBOR_PURGE_NBR)) { protocol_6lowpan_mle_purge_neighbors(cur_interface, MLE_NEIGHBOR_PURGE_NBR, true); } if (mle_neigh_cnt > (mle_6lowpan_data->nbr_of_neigh_upper_threshold - MLE_NEIGHBOR_PURGE_NBR)) { protocol_6lowpan_mle_purge_neighbors(cur_interface, MLE_NEIGHBOR_PURGE_NBR, false); } uint16_t mle_purge_timer; /* From 1.0 to 1.5 * MLE_NEIGHBOR_PURGE_TIMER */ mle_purge_timer = randLIB_randomise_base(MLE_NEIGHBOR_PURGE_TIMER_TIMEOUT, 0x8000, 0xC000); cur->mle_purge_timer = mle_purge_timer; } } // Updates blacklist timer blacklist_ttl_update(1); } } #endif } else { cur->mle_advert_timer = 0; } } static void protocol_6lowpan_nd_ready(protocol_interface_info_entry_t *cur) { if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE)) { tr_debug("ND BS ready"); bootsrap_next_state_kick(ER_BIND_COMP, cur); clear_power_state(ICMP_ACTIVE); cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY; } else { tr_debug("RE ND ready"); clear_power_state(ICMP_ACTIVE); mac_data_poll_protocol_poll_mode_disable(cur); //TRIG MLE Challenge for Normal Host if ((cur->lowpan_info & (INTERFACE_NWK_ROUTER_DEVICE | INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE | INTERFACE_NWK_BOOTSRAP_MLE)) == INTERFACE_NWK_BOOTSRAP_MLE) { //TRIG Only Normal Host #ifndef NO_MLE //GET Cordinator MLE Entry addrtype_t addrType; uint8_t tempAddr[8]; addrType = mac_helper_coordinator_address_get(cur, tempAddr); mac_neighbor_table_entry_t *neig_info = mac_neighbor_table_address_discover(mac_neighbor_info(cur), tempAddr, addrType); if (neig_info) { if (neig_info->lifetime > MLE_TABLE_CHALLENGE_TIMER) { neig_info->lifetime = (MLE_TABLE_CHALLENGE_TIMER + 1); } } #endif } } } static void protocol_6lowpan_address_reg_ready(protocol_interface_info_entry_t *cur_interface) { nd_router_t *cur; cur = nd_get_object_by_nwk_id(cur_interface->nwk_id); if (!cur) { return; } cur->nd_timer = 10; cur->ns_forward_timer = 0; uint16_t mle_timer = 0; protocol_6lowpan_nd_ready(cur_interface); if (cur_interface->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { addr_add_router_groups(cur_interface); addr_add_group(cur_interface, ADDR_REALM_LOCAL_ALL_ROUTERS); icmpv6_radv_enable(cur_interface); icmpv6_restart_router_advertisements(cur_interface, cur->border_router); /* Stop the ND revalidate timer - this means we don't do RS again */ cur->nd_re_validate = 0; mle_timer = 300; } else { if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { mac_data_poll_protocol_poll_mode_decrement(cur_interface); mle_timer = 20; } else { mle_timer = 155; } } if (cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) { if (cur->mle_advert_timer == 0) { cur->mle_advert_timer = mle_timer; cur->mle_purge_timer = MLE_NEIGHBOR_PURGE_TIMER_TIMEOUT; } } else { cur->mle_advert_timer = 0; } } void protocol_6lowpan_bootstrap_nd_ready(protocol_interface_info_entry_t *cur_interface) { tr_debug("ND Ready"); if (cur_interface->lowpan_address_mode == NET_6LOWPAN_GP64_ADDRESS) { protocol_6lowpan_address_reg_ready(cur_interface); } else { //Here we need to verify address mode tr_debug("Synch MAC16 with parent"); if (protocol_6lowpan_parent_address_synch(cur_interface, true) != 0) { nwk_bootsrap_state_update(ARM_NWK_NWK_CONNECTION_DOWN, cur_interface); } } } #ifdef HAVE_RPL static void protocol_6lowpan_bootstrap_rpl_callback(rpl_event_t event, void *handle) { protocol_interface_info_entry_t *cur = handle; if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { return; } switch (event) { case RPL_EVENT_DAO_DONE: if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE)) { bootsrap_next_state_kick(ER_BOOTSRAP_DONE, cur); clear_power_state(ICMP_ACTIVE); } else if (cur->nwk_bootstrap_state == ER_RPL_LOCAL_REPAIR) { // Updates beacon cur->bootsrap_state_machine_cnt = 0; cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; beacon_join_priority_update(cur->id); lowpan_bootstrap_pan_control(cur, true); } break; case RPL_EVENT_LOCAL_REPAIR_START: if (!(cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE)) { tr_error("RPL Local repair started"); lowpan_bootstrap_pan_control(cur, false); cur->bootsrap_state_machine_cnt = 0; cur->nwk_bootstrap_state = ER_RPL_LOCAL_REPAIR; } break; case RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS: tr_error("RPL Local repair fail-->interface to idle"); nwk_bootsrap_state_update(ARM_NWK_NWK_CONNECTION_DOWN, cur); break; default: break; } } /** * \brief Send ICMP RPL DIS message. * * \return 0 , buffer_allocation fail & 1 message sent */ uint8_t nwk_bootstrap_icmp_rpl_dis_msg_tx(protocol_interface_info_entry_t *cur) { if (cur->rpl_domain) { rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, NULL); return 1; } return 0; } /** * \brief Send ICMP RPL DIS message to bootstrap coordinator * * \return 0 , buffer_allocation fail & 1 message sent */ static uint8_t nwk_bootstrap_icmp_rpl_dis_coord_msg_tx(protocol_interface_info_entry_t *cur) { if (!cur->rpl_domain) { return 0; } uint8_t coord_address[16]; if (protocol_6lowpan_interface_get_link_local_cordinator_address(cur, coord_address) != 0) { tr_debug("Unicast DIS no coord"); return 0; } rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, coord_address); return 1; } static void nwk_rpl_dio_scan(protocol_interface_info_entry_t *cur) { if (cur->nwk_rpl_scan_counter < MAX_MC_DIS_COUNT) { if (nwk_bootstrap_icmp_rpl_dis_msg_tx(cur)) { cur->bootsrap_state_machine_cnt = 45 << cur->nwk_rpl_scan_counter; cur->nwk_rpl_scan_counter++; tr_debug("MC_DIS\n"); cur->nwk_bootstrap_state = ER_RPL_SCAN; } else { cur->bootsrap_state_machine_cnt = 3; } } else { //GivE Up Bootsrap nwk_bootsrap_state_update(ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL, cur); } } void nwk_6lowpan_rpl_router_discover(protocol_interface_info_entry_t *cur) { if (cur->rpl_domain) { tr_debug("MC DIS Force"); if (nwk_bootstrap_icmp_rpl_dis_msg_tx(cur)) { cur->nwk_bootstrap_state = ER_RPL_SCAN; cur->bootsrap_state_machine_cnt = 55; } else { cur->nwk_bootstrap_state = ER_RPL_MC; cur->bootsrap_state_machine_cnt = 15; } } else { cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; nwk_6lowpan_bootstrap_ready(cur); } } void nwk_6lowpan_rpl_router_result_check(protocol_interface_info_entry_t *cur) { if (cur->rpl_domain) { if (rpl_control_have_dodag(cur->rpl_domain)) { tr_debug("UNI DIS"); cur->bootsrap_state_machine_cnt = 0; } else { nwk_rpl_dio_scan(cur); } } else { cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; nwk_6lowpan_bootstrap_ready(cur); } } #endif void nwk_6lowpan_nd_address_registartion_ready(protocol_interface_info_entry_t *cur) { tr_debug("ND Ready!!"); cur->nwk_rpl_scan_counter = 0; #ifndef NO_MLE if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { if (protocol_6lowpan_router_multicast_synch(cur) != 0) { tr_debug("Router link request start fail"); nwk_bootsrap_state_update(ARM_NWK_NWK_CONNECTION_DOWN, cur); } #ifdef HAVE_RPL if (protocol_6lowpan_rpl_domain) { // arm_nwk_6lowpan_rpl_dodag_poison from a previous connection may have left force_leaf set rpl_control_force_leaf(protocol_6lowpan_rpl_domain, false); rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, true); rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, NULL, NULL, NULL, cur); } // Send unicast DIS to coordinator nwk_bootstrap_icmp_rpl_dis_coord_msg_tx(cur); #endif /* HAVE_RPL */ } else { //No point to update link if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST || cur->lowpan_address_mode != NET_6LOWPAN_GP64_ADDRESS) { if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST) { cur->lowpan_info |= INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE; tr_debug("Enable Poll state"); mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, false); mac_data_poll_init(cur); mac_data_poll_init_protocol_poll(cur); } if (protocol_6lowpan_parent_address_synch(cur, false) != 0) { nwk_bootsrap_state_update(ARM_NWK_NWK_CONNECTION_DOWN, cur); } } else { cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; nwk_6lowpan_bootstrap_ready(cur); } } #else #ifdef HAVE_RPL cur->nwk_bootstrap_state = ER_RPL_SCAN; nwk_6lowpan_rpl_router_result_check(cur); #else cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; nwk_6lowpan_bootstrap_ready(cur); #endif #endif } #ifdef PANA void nwk_6lowpan_pana_key_pull(protocol_interface_info_entry_t *cur) { //REG GP16 address if (pana_ping_notify_msg_tx(cur->mac_parameters->pan_id) == 0) { tr_warn("PING TX fail"); cur->nwk_bootstrap_state = ER_PANA_PING; cur->bootsrap_state_machine_cnt = 2; } } #endif #ifndef NO_MLE #ifdef PANA void nwk_6lowpan_bootsrap_pana_authentication_cb(bool processSuccesfully, protocol_interface_info_entry_t *cur) { if (processSuccesfully) { bootsrap_next_state_kick(ER_PANA_AUTH_DONE, cur); } else { bootsrap_next_state_kick(ER_PANA_AUTH_ERROR, cur); } } static void nwk_6lowpan_bootsrap_pana_authentication_start(protocol_interface_info_entry_t *cur) { uint8_t temp_coordinator_address[16]; pana_tls_setup_s setup; sec_suite_t *suite = 0; tr_debug("Wake Pana by Bootsrap"); protocol_6lowpan_interface_get_link_local_cordinator_address(cur, temp_coordinator_address); //Release old before copy new if (cur->pana_sec_info_temp == 0) { tr_debug("Allocate Pana auth Info"); cur->pana_sec_info_temp = ns_dyn_mem_alloc(sizeof(auth_info_t)); } if (cur->if_lowpan_security_params->pana_params) { setup.psk_key_id = cur->if_lowpan_security_params->pana_params->psk_key_id; switch (cur->if_lowpan_security_params->pana_params->nwk_chipher_mode) { case NET_TLS_PSK_CIPHER: /**< Network Authentication support only PSK */ setup.security_support = SEC_CIPHERSUITE_PSK; break; case NET_TLS_ECC_CIPHER: /**< Network Authentication support only ECC */ setup.security_support = SEC_CIPHERSUITE_ECC; break; case NET_TLS_PSK_AND_ECC_CIPHER: setup.security_support = SEC_CIPHERSUITE_PSK | SEC_CIPHERSUITE_ECC; break; } setup.pan_id = cur->mac_parameters->pan_id; suite = pana_client_init(cur->pana_sec_info_temp, temp_coordinator_address, &setup); } if (suite) { //SET address //SET CORD Address nd_router_t *object = nd_get_pana_address(); cur->nwk_bootstrap_state = ER_PANA_AUTH; cur->bootsrap_state_machine_cnt = 0; if (object) { icmp_nd_set_nd_def_router_address(suite->session_address, object); tr_debug("ND Router adr: %s", trace_ipv6(suite->session_address)); //SET CORD ADDRESS if (memcmp(&suite->session_address[8], ADDR_SHORT_ADR_SUFFIC, 6) == 0) { mac_helper_coordinator_address_set(cur, ADDR_802_15_4_SHORT, &(suite->session_address[14])); } else { suite->session_address[8] ^= 2; mac_helper_coordinator_address_set(cur, ADDR_802_15_4_LONG, &(suite->session_address[8])); suite->session_address[8] ^= 2; } } else { tr_debug("Use Mac Coordinator"); } suite->session_port = UDP_PORT_PANA; suite->interface = cur; } else { cur->nwk_bootstrap_state = ER_PANA_AUTH_ERROR; cur->bootsrap_state_machine_cnt = 1; } } #endif #endif static void coordinator_black_list(protocol_interface_info_entry_t *cur) { uint8_t coord_pan_address[10]; addrtype_t cord_adr_type = mac_helper_coordinator_address_get(cur, coord_pan_address + 2); if (cord_adr_type != ADDR_NONE) { uint16_t pana_id = mac_helper_panid_get(cur); common_write_16_bit(pana_id, coord_pan_address); if (cord_adr_type == ADDR_802_15_4_SHORT) { memset(coord_pan_address + 4, 0, 6); } pan_cordinator_blacklist_pan_set(&cur->pan_cordinator_black_list, coord_pan_address, 300); } } static void nwk_6lowpan_network_authentication_fail(protocol_interface_info_entry_t *cur) { nwk_scan_params_t *scan_params = &cur->mac_parameters->nwk_scan_params; tr_warn("Pana Auhth er"); scan_params->nwk_cur_active = mac_helper_free_pan_descriptions(scan_params->nwk_cur_active); //Black List coordinator coordinator_black_list(cur); nwk_bootsrap_state_update(ARM_NWK_AUHTENTICATION_FAIL, cur); } static void nwk_protocol_network_key_set_from_pana(protocol_interface_info_entry_t *cur) { uint8_t *key_ptr = pana_key_get(cur->pana_sec_info_temp->network_key); if (key_ptr) { mac_helper_security_default_key_set(cur, (key_ptr + 16), cur->pana_sec_info_temp->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, cur->pana_sec_info_temp->key_id, true); if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } } } uint8_t *protocol_6lowpan_mle_service_security_notify_cb(int8_t interface_id, mle_security_event_t event, uint8_t keyId) { (void)keyId; protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(interface_id); if (!interface) { return NULL; } switch (event) { case MLE_SEC_MAX_FRAME_COUNTER_REACHED: break; case MLE_SEC_KEY_UPDATE_NOTIFY: //Call MAC update mac_helper_security_key_swap_next_to_default(interface); break; case MLE_SEC_UNKNOWN_KEY: break; } return NULL; } static void nwk_protocol_network_key_init_from_pana(protocol_interface_info_entry_t *cur) { uint8_t *key_ptr = pana_key_get(cur->pana_sec_info_temp->network_key); if (key_ptr) { mac_helper_security_default_key_set(cur, (key_ptr + 16), cur->pana_sec_info_temp->key_id, MAC_KEY_ID_MODE_IDX); //mac_security_interface_link_frame_counter_reset(cur->id); mac_helper_default_security_level_set(cur, SEC_ENC_MIC32); mac_helper_default_security_key_id_mode_set(cur, MAC_KEY_ID_MODE_IDX); //Init MLE Frame counter and key's and security mle_service_security_init(cur->id, SEC_ENC_MIC32, cur->if_lowpan_security_params->mle_security_frame_counter, NULL, protocol_6lowpan_mle_service_security_notify_cb); mle_service_security_set_security_key(cur->id, key_ptr, cur->pana_sec_info_temp->key_id, true); mle_service_security_set_frame_counter(cur->id, cur->if_lowpan_security_params->mle_security_frame_counter); } } static void nwk_6lowpan_network_authentication_done(protocol_interface_info_entry_t *cur) { if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) { mac_helper_free_scan_confirm(&cur->mac_parameters->nwk_scan_params); if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION) { nwk_protocol_network_key_init_from_pana(cur); } else { tr_debug("SET NO security"); mac_helper_default_security_level_set(cur, SEC_NONE); } #ifndef NO_MLE if (protocol_6lowpan_parent_link_req(cur) != 0) { tr_debug("Link request start fail"); } #else pan_coordinator_blacklist_free(&cur->pan_cordinator_black_list); cur->nwk_bootstrap_state = ER_SCAN; nwk_6lowpan_router_scan_state(cur); #endif } else { mac_data_poll_protocol_poll_mode_disable(cur); if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) { tr_debug("PULL kEY Done by Host"); cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; nwk_6lowpan_bootstrap_ready(cur); } else { tr_debug("PULL kEY Done by Router"); #ifdef PANA cur->nwk_bootstrap_state = ER_PANA_PING; nwk_6lowpan_pana_key_pull(cur); #endif } nwk_protocol_network_key_set_from_pana(cur); #ifndef NO_TLS #endif } } bool protocol_6lowpan_bootsrap_link_set(protocol_interface_info_entry_t *interface, mlme_pan_descriptor_t *pan_descriptor, const uint8_t *beacon_payload, uint8_t beacon_length) { mlme_start_t start_req; memset(&start_req, 0, sizeof(mlme_start_t)); mac_helper_coordinator_address_set(interface, (addrtype_t)pan_descriptor->CoordAddrMode, pan_descriptor->CoordAddress); interface->mac_parameters->mac_channel = pan_descriptor->LogicalChannel; interface->mac_parameters->pan_id = pan_descriptor->CoordPANId; if (interface->nwk_wpan_nvm_api) { wpan_nvm_params_t *params = interface->nwk_wpan_nvm_api->nvm_params_get_cb(interface->nwk_wpan_nvm_api, pan_descriptor->CoordPANId); interface->if_lowpan_security_params->mle_security_frame_counter = params->mle_securit_counter; //SET MAC and MLE security frame counters mle_service_security_set_frame_counter(interface->id, params->mle_securit_counter); mac_helper_link_frame_counter_set(interface->id, params->mac_security_frame_counter); } start_req.PANId = pan_descriptor->CoordPANId; start_req.LogicalChannel = pan_descriptor->LogicalChannel; start_req.ChannelPage = 0; start_req.BeaconOrder = pan_descriptor->SuperframeSpec[0] >> 4; start_req.SuperframeOrder = pan_descriptor->SuperframeSpec[0] & 0x0f; //SET Beacon Payload uint8_t *b_ptr = mac_helper_beacon_payload_reallocate(interface, beacon_length); if (!b_ptr) { tr_error("Beacon Payload allocate Fail"); bootsrap_next_state_kick(ER_BOOTSTRAP_SCAN_FAIL, interface); return false; } memcpy(b_ptr, beacon_payload, beacon_length); mac_helper_beacon_payload_register(interface); //Start and set pan-id interface->mac_api->mlme_req(interface->mac_api, MLME_START, &start_req); mac_helper_panid_set(interface, pan_descriptor->CoordPANId); return true; } bool protocol_6lowpan_bootsrap_start(protocol_interface_info_entry_t *interface) { net_load_balance_internal_state_activate(interface, false); //SET allways RX ON Idle device by default mac_helper_pib_boolean_set(interface, macRxOnWhenIdle, true); interface->lowpan_info &= ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE; mac_data_poll_init(interface); mac_helper_mac16_address_set(interface, 0xffff); tr_debug("Mac Ready"); interface->nwk_nd_re_scan_count = 2; if (interface->if_lowpan_security_params->nwk_security_mode == NET_SEC_MODE_PSK_LINK_SECURITY) { tr_debug("SET Security Mode"); mac_helper_default_security_level_set(interface, interface->mac_parameters->mac_configured_sec_level); mac_helper_default_security_key_id_mode_set(interface, MAC_KEY_ID_MODE_IDX); } //Check first pana and then MLE and else start RS scan pahse if (interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION) { #ifdef PANA nwk_6lowpan_bootsrap_pana_authentication_start(interface); tr_debug("Pana auth"); #else bootsrap_next_state_kick(ER_BOOTSTRAP_SCAN_FAIL, interface); return false; #endif } else if (interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) { if (protocol_6lowpan_parent_link_req(interface) != 0) { bootsrap_next_state_kick(ER_BOOTSTRAP_SCAN_FAIL, interface); return false; } } else { bootsrap_next_state_kick(ER_SCAN, interface); } return true; } void protocol_6lowpan_mac_scan_confirm(int8_t if_id, const mlme_scan_conf_t *conf) { nwk_pan_descriptor_t *result; nwk_pan_descriptor_t *best; protocol_interface_info_entry_t *interface = NULL; if (conf->ScanType != MAC_ACTIVE_SCAN) { return; } interface = protocol_stack_interface_info_get_by_id(if_id); if (!interface) { tr_debug("Mac scan confirm:Unknow Interface"); return; } bool is_border_router = false; if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { is_border_router = true; } interface->mac_parameters->nwk_scan_params.active_scan_active = false; result = arm_net_get_scanned_nwk_list(if_id); if (!result || !conf->ResultListSize) { tr_debug("Mac scan confirm:No Beacons"); if (is_border_router == false) { bootsrap_next_state_kick(ER_BOOTSTRAP_SCAN_FAIL, interface); return; } } //Analyze Best Result best = mac_helper_select_best_lqi(result); mac_helper_drop_selected_from_the_scanresult(&interface->mac_parameters->nwk_scan_params, best); bool link_start_ok = false; if (is_border_router == false) { link_start_ok = protocol_6lowpan_bootsrap_link_set(interface, best->pan_descriptor, best->beacon_payload, best->beacon_length); } mac_helper_free_scan_confirm(&interface->mac_parameters->nwk_scan_params); best = mac_helper_free_pan_descriptions(best); if (link_start_ok) { protocol_6lowpan_bootsrap_start(interface); } if (is_border_router == true) { if (interface->nwk_bootstrap_state == ER_WARM_ACTIVE_SCAN) { border_router_start(interface, true); interface->bootsrap_state_machine_cnt = 0; interface->nwk_bootstrap_state = ER_BOOTSRAP_DONE; } else { border_router_start(interface, false); } } } void bootstrap_timer_handle(uint16_t ticks) { (void)ticks; ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) { if (cur->nwk_id == IF_6LoWPAN) { if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN || cur->nwk_bootstrap_state == ER_WARM_ACTIVE_SCAN) { // Retransmit Scan request bootsrap_next_state_kick(cur->nwk_bootstrap_state, cur); tr_error("Restart active scan"); } else { // Retransmit Start request mlme_start_t start_req; memset(&start_req, 0, sizeof(mlme_start_t)); start_req.PANId = cur->border_router_setup->mac_panid; start_req.LogicalChannel = cur->mac_parameters->mac_channel; start_req.ChannelPage = 0; start_req.BeaconOrder = 0x0f; start_req.SuperframeOrder = 0x0f; start_req.PANCoordinator = 1; if (cur->mac_api) { cur->mac_api->mlme_req(cur->mac_api, MLME_START, (void *)&start_req); tr_error("Restart MAC"); } } } } } void protocol_6lowpan_bootstrap(protocol_interface_info_entry_t *cur) { switch (cur->nwk_bootstrap_state) { case ER_ACTIVE_SCAN: case ER_WARM_ACTIVE_SCAN: tr_debug("Start Active Scan"); cur->mac_parameters->nwk_scan_params.stack_chan_list = cur->mac_parameters->mac_channel_list; mlme_scan_t req; mac_create_scan_request(MAC_ACTIVE_SCAN, &cur->mac_parameters->mac_channel_list, cur->mac_parameters->nwk_scan_params.scan_duration, &req); if (cur->mac_api) { cur->scan_cb = protocol_6lowpan_mac_scan_confirm; cur->mac_parameters->nwk_scan_params.active_scan_active = true; if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { protocol_timer_start(PROTOCOL_TIMER_BOOTSTRAP_TIM, bootstrap_timer_handle, BOOTSTRAP_SCAN_TIMEOUT); } cur->mac_api->mlme_req(cur->mac_api, MLME_SCAN, &req); } break; case ER_SCAN: //LED1_TOGGLE(); nwk_6lowpan_router_scan_state(cur); break; case ER_PANA_AUTH_ERROR: nwk_6lowpan_network_authentication_fail(cur); break; case ER_PANA_AUTH_DONE: nwk_6lowpan_network_authentication_done(cur); break; case ER_BIND_COMP: nwk_6lowpan_nd_address_registartion_ready(cur); break; #ifdef HAVE_RPL case ER_RPL_MC: nwk_6lowpan_rpl_router_discover(cur); break; case ER_RPL_SCAN: nwk_6lowpan_rpl_router_result_check(cur); break; #endif case ER_BOOTSRAP_DONE: nwk_6lowpan_bootstrap_ready(cur); break; case ER_PARENT_SYNCH_LOST: tr_debug("-->Parent synch Lose"); nwk_bootsrap_state_update(ARM_NWK_NWK_PARENT_POLL_FAIL, cur); break; case ER_BOOTSTRAP_CONNECTION_DOWN: nwk_bootsrap_state_update(ARM_NWK_NWK_CONNECTION_DOWN, cur); break; case ER_BOOTSTRAP_IP_ADDRESS_ALLOC_FAIL: nwk_bootsrap_state_update(ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL, cur); tr_info("-->idle"); break; case ER_BOOTSTRAP_DAD_FAIL: nwk_bootsrap_state_update(ARM_NWK_DUPLICATE_ADDRESS_DETECTED, cur); break; case ER_BOOTSTRAP_SCAN_FAIL: tr_debug("Network Bootsrap Start Fail"); nwk_bootsrap_state_update(ARM_NWK_NWK_SCAN_FAIL, cur); break; #ifdef PANA case ER_PANA_PING: nwk_6lowpan_pana_key_pull(cur); break; #endif case ER_MLE_LINK_REQ: //No need to do anything in this case break; default: tr_error("Unknow state %d", cur->nwk_bootstrap_state); } } void protocol_6lowpan_nd_borderrouter_connection_down(protocol_interface_info_entry_t *interface) { /*if (rpl_object_poisons() == 0) ??? */ { mac_helper_mac16_address_set(interface, 0xffff); //TRIG Event for ND connection Down bootsrap_next_state_kick(ER_BOOTSTRAP_IP_ADDRESS_ALLOC_FAIL, interface); } } void protocol_6lowpan_bootstrap_re_start(protocol_interface_info_entry_t *interface) { mac_helper_mac16_address_set(interface, 0xffff); arm_6lowpan_bootstrap_init(interface); tr_info("-->Bootsrap"); } uint8_t *protocol_6lowpan_nd_border_router_address_get(nwk_interface_id nwk_id) { nd_router_t *object = nd_get_object_by_nwk_id(nwk_id); if (object) { return object->border_router; } return 0; } uint8_t protocol_6lowpan_rf_link_scalability_from_lqi(uint8_t lqi) { uint8_t i = 16; if (lqi >= 240) { i = 1; } else { lqi /= 16; if (lqi) { i = (16 - lqi); } } return i; } int protocol_6lowpan_del_ll16(protocol_interface_info_entry_t *cur, uint16_t mac_short_address) { uint8_t address[16]; memcpy(address, ADDR_LINK_LOCAL_PREFIX, 8); memcpy(address + 8, ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(mac_short_address, &address[14]); return addr_delete(cur, address); } int protocol_6lowpan_set_ll16(protocol_interface_info_entry_t *cur, uint16_t mac_short_address) { if_address_entry_t *address_entry; uint8_t address[16]; memcpy(address, ADDR_LINK_LOCAL_PREFIX, 8); memcpy(address + 8, ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(mac_short_address, &address[14]); address_entry = addr_add(cur, address, 64, ADDR_SOURCE_UNKNOWN, 0xffffffff, 0xffffffff, false); if (address_entry) { return 0; } return -1; } static void protocol_6lowpan_generate_link_reject(protocol_interface_info_entry_t *cur, const mlme_comm_status_t *status) { uint8_t address[16]; memcpy(address, ADDR_LINK_LOCAL_PREFIX, 8); if (status->SrcAddrMode == MAC_ADDR_MODE_16_BIT) { memcpy(address + 8, ADDR_SHORT_ADR_SUFFIC, 6); memcpy(address + 14, status->SrcAddr, 2); } else { memcpy(address + 8, status->SrcAddr, 8); address[8] ^= 2; } if (mac_helper_default_security_level_get(cur)) { tr_debug("Drop link by asymmetric security"); mle_service_reject_message_build(cur->id, address, false); return; } } static void lowpan_comm_status_indication_cb(int8_t if_id, const mlme_comm_status_t *status) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(if_id); if (!cur) { return; } mac_neighbor_table_entry_t *entry_ptr; switch (status->status) { case MLME_UNSUPPORTED_SECURITY: case MLME_UNAVAILABLE_KEY: /* Generate MLE Link Reject to destination */ if (status->DstAddrMode == MAC_ADDR_MODE_16_BIT && status->DstAddr[0] == 0xff && status->DstAddr[1] == 0xff) { return; //Drop brodcast security failure } if (!cur->mle_link_reject_tokens) { return; } cur->mle_link_reject_tokens--; protocol_6lowpan_generate_link_reject(cur, status); break; case MLME_DATA_POLL_NOTIFICATION: entry_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), status->SrcAddr, status->SrcAddrMode); if (entry_ptr) { // Refresh Timeout mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), entry_ptr, entry_ptr->link_lifetime); } break; default: break; } } bool lowpan_neighbour_data_clean(int8_t interface_id, const uint8_t *link_local_address) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return false; } bool return_value = false; mac_neighbor_table_entry_t *neigh_entry = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), link_local_address, false, NULL); if (neigh_entry) { //Remove entry if (neigh_entry->link_role == PRIORITY_PARENT_NEIGHBOUR || neigh_entry->link_role == SECONDARY_PARENT_NEIGHBOUR) { return_value = true; } mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), neigh_entry); } return return_value; } void protocol_6lowpan_mle_timer(uint16_t ticks_update) { #ifndef NO_MLE if (mle_6lowpan_data) { /* Three request in burst and after that one link request per second */ mle_6lowpan_data->link_req_token_bucket += ticks_update; if (mle_6lowpan_data->link_req_token_bucket > MLE_LINK_REQ_TOKEN_BUCKET_SIZE) { mle_6lowpan_data->link_req_token_bucket = MLE_LINK_REQ_TOKEN_BUCKET_SIZE; } } #endif } #endif