/* * Copyright (c) 2013-2017, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "nsconfig.h" #include "MLE/mle.h" #ifndef NO_MLE #include "ns_types.h" #include "eventOS_event.h" #include "eventOS_event_timer.h" #include "socket_api.h" #include "Core/include/socket.h" #include "nsdynmemLIB.h" #include "ns_trace.h" #include "string.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/udp.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h" #include "platform/arm_hal_interrupt.h" #include "platform/topo_trace.h" #include "common_functions.h" #include "MLE/mle_tlv.h" #include "NWK_INTERFACE/Include/protocol_timer.h" #include "Common_Protocols/ipv6_constants.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "Service_Libs/etx/etx.h" #include "6LoWPAN/MAC/mac_helper.h" #include "mac_api.h" #include "6LoWPAN/MAC/mac_data_poll.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #define MLE_UNICAST_CHALLENGE_TIMEOUT 20 #define TRACE_GROUP "mle" typedef enum { ARM_MLE_INIT = 0, ARM_MLE_TTL_TIMER } arm_mle_event_id_e; //MLE class structure typedef struct mle_table_class { int8_t interfaceId; mle_class_user_mode mode; mle_neigh_table_list_t mle_table; //Active Entry mle_neigh_table_list_t free_enty_list; mle_neigh_table_entry_t *allocated_buffer; uint8_t buffer_size; mle_entry_user_entry_remove_notify *remove_cb; mle_entry_link_keep_alive *keep_alive_cb; mle_entry_link_keep_alive *challenge_cb; mle_entry_interface_activate *interface_is_active; ns_list_link_t link; /*!< List link entry */ } mle_table_class_t; static NS_LIST_DEFINE(mle_table_calss_list, mle_table_class_t, link); static int8_t mle_tasklet_id = -1; static arm_event_storage_t *mle_class_timer_storage = NULL; static mle_neigh_table_entry_t *mle_class_neighbor_get(mle_neigh_table_list_t *mle_table, const uint8_t *address, addrtype_t type); static mle_neigh_table_entry_t *mle_class_get_free_entry(mle_neigh_table_list_t *mle_table); static bool mle_class_neighbor_validate(mle_neigh_table_list_t *mle_table, const mle_neigh_table_entry_t *entry); static void mle_event_handler(arm_event_s *event); static bool mle_table_timer_start(void) { if (!mle_class_timer_storage) { arm_event_s event = { .receiver = mle_tasklet_id, .sender = 0, .event_id = 0, .data_ptr = NULL, .event_type = ARM_MLE_TTL_TIMER, .priority = ARM_LIB_LOW_PRIORITY_EVENT, }; mle_class_timer_storage = eventOS_event_timer_request_every(&event, eventOS_event_timer_ms_to_ticks(MLE_TIMER_TICKS_MS)); if (!mle_class_timer_storage) { tr_error("Mle timer start fail"); return false; } } return true; } static void mle_table_timer_stop(void) { if (mle_class_timer_storage && ns_list_is_empty(&mle_table_calss_list)) { eventOS_cancel(mle_class_timer_storage); mle_class_timer_storage = NULL; } } static void mle_table_remove_free_indirect_table(int8_t interface_id, mle_neigh_table_entry_t *entry_ptr) { protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id); if (!cur_interface) { return; } //Free firts by defined short address if (entry_ptr->short_adr < 0xfffe) { uint8_t temp_address[2]; common_write_16_bit(entry_ptr->short_adr, temp_address); lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT); } lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG); } static void mle_table_class_list_free(mle_table_class_t *mle_table_class) { ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_table_class->mle_table) { ns_list_remove(&mle_table_class->mle_table, cur); //Clean Indirect queue mle_table_remove_free_indirect_table(mle_table_class->interfaceId, cur); //Call Remove callback mle_table_class->remove_cb(mle_table_class->interfaceId, cur); //Removes ETX neighbor etx_neighbor_remove(mle_table_class->interfaceId, cur); ns_list_add_to_start(&mle_table_class->free_enty_list, cur); } topo_trace(TOPOLOGY_MLE, NULL, TOPO_CLEAR); } static void mle_table_class_free(mle_table_class_t *main_list) { ns_list_remove(&mle_table_calss_list, main_list); mle_table_class_list_free(main_list); //Free list buffer ns_dyn_mem_free(main_list->allocated_buffer); ns_dyn_mem_free(main_list); mle_table_timer_stop(); } static int8_t mle_table_class_table_buffer_allocate(mle_table_class_t *mle_class, uint8_t list_size) { mle_neigh_table_entry_t *list_buffer = ns_dyn_mem_alloc(sizeof(mle_neigh_table_entry_t) * list_size); if (!list_buffer) { return -1; } mle_class->allocated_buffer = list_buffer; //Save storaged ns_list_init(&mle_class->free_enty_list); ns_list_init(&mle_class->mle_table); for (uint8_t i = 0; i< list_size; i++) { memset(list_buffer, 0, sizeof(mle_neigh_table_entry_t)); list_buffer->attribute_index = i; //Add to list ns_list_add_to_end(&mle_class->free_enty_list,list_buffer); list_buffer++; } return 0; } static mle_table_class_t * mle_table_class_allocate(int8_t interfaceId, uint8_t list_size) { mle_table_class_t *newClass = ns_dyn_mem_alloc(sizeof(mle_table_class_t)); if (newClass) { memset(newClass, 0, sizeof(mle_table_class_t)); if (mle_table_class_table_buffer_allocate(newClass,list_size) != 0) { ns_dyn_mem_free(newClass); return NULL; } newClass->interfaceId = interfaceId; newClass->buffer_size = list_size; } return newClass; } static mle_table_class_t * mle_table_class_discover(int8_t interface_id) { ns_list_foreach(mle_table_class_t, cur_mle_class, &mle_table_calss_list) { if (cur_mle_class->interfaceId == interface_id) { return cur_mle_class; } } return NULL; } static int8_t mle_class_event_handler_init(void) { if (mle_tasklet_id == -1) { //GENERATE TASKLET mle_tasklet_id = eventOS_event_handler_create(&mle_event_handler, ARM_MLE_INIT); } return mle_tasklet_id; } int8_t mle_class_init(int8_t interface_id, uint8_t table_size, mle_entry_user_entry_remove_notify *remove_cb, mle_entry_link_keep_alive *keep_alive_cb, mle_entry_interface_activate *interface_is_active) { //Discover from the list mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (mle_class_ptr) { mle_class_ptr->remove_cb = remove_cb; mle_class_ptr->keep_alive_cb = keep_alive_cb; mle_class_ptr->challenge_cb = NULL; mle_class_ptr->interface_is_active = interface_is_active; if (mle_class_ptr->buffer_size != table_size) { //Clean tabs only when table size is different mle_table_class_list_free(mle_class_ptr); ns_dyn_mem_free(mle_class_ptr->allocated_buffer); mle_class_ptr->allocated_buffer = NULL; //Reallocate if (mle_table_class_table_buffer_allocate(mle_class_ptr,table_size) != 0) { ns_list_remove(&mle_table_calss_list, mle_class_ptr); ns_dyn_mem_free(mle_class_ptr); return -2; } mle_class_ptr->buffer_size = table_size; } return 0; } if (mle_class_event_handler_init() < 0) { return -2; } if (!mle_table_timer_start()) { return -2; } mle_class_ptr = mle_table_class_allocate(interface_id, table_size); //Allocate new if (!mle_class_ptr) { return -2; } tr_debug("MLE service init size %d", table_size); mle_class_ptr->remove_cb = remove_cb; mle_class_ptr->keep_alive_cb = keep_alive_cb; mle_class_ptr->challenge_cb = NULL; mle_class_ptr->interface_is_active = interface_is_active; ns_list_add_to_end(&mle_table_calss_list, mle_class_ptr); return 0; } int8_t mle_class_router_challenge(int8_t interface_id,mle_entry_link_keep_alive *challenge_cb) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return -1; } mle_class_ptr->challenge_cb = challenge_cb; return 0; } bool mle_class_exists_for_interface(int8_t interface_id) { if (mle_table_class_discover(interface_id)) { return true; } return false; } int8_t mle_class_deallocate(int8_t interface_id) { //Discover from the list mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return -1; } mle_table_class_free(mle_class_ptr); return 0; } int8_t mle_class_list_clean(int8_t interface_id) { //Discover from the list mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return -1; } mle_table_class_list_free(mle_class_ptr); return 0; } int8_t mle_class_mode_set(int8_t interface_id,mle_class_user_mode mode) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return -1; } mle_class_ptr->mode = mode; return 0; } int8_t mle_class_set_new_key_pending(int8_t interface_id) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); if (!mle_class_ptr) { return -1; } ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_class_ptr->mle_table) { cur->new_key_pending = true; } return 0; } int16_t mle_class_free_entry_count_get(int8_t interface_id) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return 0; } return ns_list_count(&(mle_class_ptr->free_enty_list)); } int16_t mle_class_sleepy_entry_count_get(int8_t interface_id) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); if (!mle_class_ptr) { return 0; } uint16_t count = 0; ns_list_foreach(mle_neigh_table_entry_t, entry, &mle_class_ptr->mle_table) { if (!(entry->mode & MLE_RX_ON_IDLE)) { count++; } } return count; } int16_t mle_class_rfd_entry_count_get(int8_t interface_id) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); if (!mle_class_ptr) { return 0; } uint16_t count = 0; ns_list_foreach(mle_neigh_table_entry_t, entry, &mle_class_ptr->mle_table) { if ((entry->mode & MLE_DEV_MASK) == MLE_RFD_DEV) { count++; } } return count; } mle_neigh_table_entry_t *mle_class_get_entry_by_ll64(int8_t interface_id, uint8_t linkMargin, const uint8_t *ipv6Address, bool allocateNew, bool *new_entry_allocated) { // Check it really is LL64 (not LL16) if (memcmp(ipv6Address, ADDR_LINK_LOCAL_PREFIX , 8) != 0) { return NULL; //Mot Link Local Address } if (memcmp((ipv6Address + 8), ADDR_SHORT_ADR_SUFFIC , 6) == 0) { return NULL; } // map uint8_t temporary_mac64[8]; memcpy(temporary_mac64, (ipv6Address + 8), 8); temporary_mac64[0] ^= 2; return mle_class_get_entry_by_mac64(interface_id, linkMargin, temporary_mac64, allocateNew, new_entry_allocated); } mle_neigh_table_entry_t *mle_class_discover_entry_by_ll64(int8_t interface_id, const uint8_t *ipv6Address) { // Check it really is LL64 (not LL16) if (memcmp(ipv6Address, ADDR_LINK_LOCAL_PREFIX , 8) != 0) { return NULL; //Mot Link Local Address } if (memcmp((ipv6Address + 8), ADDR_SHORT_ADR_SUFFIC , 6) == 0) { return NULL; } // map uint8_t temporary_mac64[8]; memcpy(temporary_mac64, (ipv6Address + 8), 8); temporary_mac64[0] ^= 2; return mle_class_get_by_link_address(interface_id, temporary_mac64, ADDR_802_15_4_LONG); } mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8_t linkMargin, const uint8_t *mac64, bool allocateNew, bool *new_entry_allocated) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return NULL; } if (new_entry_allocated) { *new_entry_allocated = false; } mle_neigh_table_entry_t *ret_val = mle_class_neighbor_get(&mle_class_ptr->mle_table, mac64, ADDR_802_15_4_LONG); /* Look for existing entry */ if (ret_val) { ret_val->link_margin = ret_val->link_margin + linkMargin - (ret_val->link_margin >> THREAD_LINK_MARGIN_SCALING); return ret_val; } if (allocateNew) { ret_val = mle_class_get_free_entry(&mle_class_ptr->free_enty_list); if (ret_val) { //Add to active list ns_list_add_to_start(&mle_class_ptr->mle_table, ret_val); topo_trace(TOPOLOGY_MLE, mac64, TOPO_ADD); ret_val->link_margin = linkMargin << THREAD_LINK_MARGIN_SCALING; memcpy(ret_val->mac64, mac64, 8); if (new_entry_allocated) { *new_entry_allocated = true; } } } return ret_val; } static mle_neigh_table_entry_t *mle_class_neighbor_get_by_attribute_index(mle_neigh_table_list_t *mle_table, uint8_t attribute_index) { ns_list_foreach(mle_neigh_table_entry_t, cur, mle_table) { if (cur->attribute_index == attribute_index) { return cur; } } return NULL; } static bool mle_class_neighbor_validate(mle_neigh_table_list_t *mle_table, const mle_neigh_table_entry_t *entry) { ns_list_foreach(mle_neigh_table_entry_t, cur, mle_table) { if (cur == entry) { return true; } } return false; } static mle_neigh_table_entry_t *mle_class_neighbor_get(mle_neigh_table_list_t *mle_table, const uint8_t *address, addrtype_t type) { uint16_t short_id; if (type == ADDR_802_15_4_SHORT) { short_id = common_read_16_bit(address); } ns_list_foreach(mle_neigh_table_entry_t, cur, mle_table) { if (type == ADDR_802_15_4_SHORT) { if (cur->short_adr == short_id) { return cur; } } else { if (memcmp(cur->mac64, address, 8) == 0) { return cur; } } } return NULL; } static mle_neigh_table_entry_t *mle_class_get_free_entry(mle_neigh_table_list_t *mle_table) { mle_neigh_table_entry_t *mle_entry = ns_list_get_first(mle_table); if (mle_entry) { //Remove from the list ns_list_remove(mle_table, mle_entry); uint8_t attribute_id = mle_entry->attribute_index; memset(mle_entry, 0, sizeof(mle_neigh_table_entry_t)); mle_entry->attribute_index = attribute_id; mle_entry->short_adr = 0xffff; mle_entry->mode = MLE_FFD_DEV | MLE_RX_ON_IDLE; mle_entry->holdTime = 7; mle_entry->last_contact_time = protocol_core_monotonic_time; mle_entry->mle_frame_counter = 0; mle_entry->last_key_sequence = 0; mle_entry->new_key_pending = false; mle_entry->medium_ttl_challenge = false; } return mle_entry; } mle_neigh_table_entry_t *mle_class_get_by_link_address(int8_t interface_id, const uint8_t *address, addrtype_t type) { switch (type) { case ADDR_802_15_4_SHORT: case ADDR_802_15_4_LONG: break; default: return NULL; } mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return NULL; } return mle_class_neighbor_get(&mle_class_ptr->mle_table, address, type); } mle_neigh_table_entry_t *mle_class_get_by_device_attribute_id(int8_t interface_id, uint8_t attribute_index) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return NULL; } return mle_class_neighbor_get_by_attribute_index(&mle_class_ptr->mle_table, attribute_index); } int8_t mle_class_remove_entry(int8_t interface_id, mle_neigh_table_entry_t *entry) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return -1; } //Validate Pointer if (!mle_class_neighbor_validate(&mle_class_ptr->mle_table, entry)) { return -2; } //Remove from list ns_list_remove(&mle_class_ptr->mle_table, entry); //Free Indirect Queue mle_table_remove_free_indirect_table(mle_class_ptr->interfaceId, entry); //Call Remove callback mle_class_ptr->remove_cb(mle_class_ptr->interfaceId, entry); topo_trace(TOPOLOGY_MLE, entry->ext64, TOPO_REMOVE); //Removes ETX neighbor etx_neighbor_remove(interface_id, entry); //Add to free list ns_list_add_to_start(&mle_class_ptr->free_enty_list, entry); return 0; } int8_t mle_class_remove_neighbour(int8_t interface_id, const uint8_t *address, addrtype_t type) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return -1; } mle_neigh_table_entry_t * entry = mle_class_get_by_link_address(interface_id, address, type); if (!entry) { return -2; } //Remove from list ns_list_remove(&mle_class_ptr->mle_table, entry); //Free Indirect Queue mle_table_remove_free_indirect_table(mle_class_ptr->interfaceId, entry); //Call Remove callback mle_class_ptr->remove_cb(mle_class_ptr->interfaceId, entry); topo_trace(TOPOLOGY_MLE, entry->ext64, TOPO_REMOVE); //Removes ETX neighbor etx_neighbor_remove(interface_id, entry); //Add to free list ns_list_add_to_start(&mle_class_ptr->free_enty_list, entry); return 0; } static void mle_class_table_ttl(uint16_t ticks, mle_table_class_t *mle_class_ptr) { uint16_t new_ttl; bool challengeCheck; bool remove_entry; //validate that interface is still active if (!mle_class_ptr->interface_is_active(mle_class_ptr->interfaceId)) { return; } ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_class_ptr->mle_table) { new_ttl = 0; remove_entry = false; switch (mle_class_ptr->mode) { case MLE_CLASS_END_DEVICE: if (cur->priorityFlag) { challengeCheck = true; } else { challengeCheck = false; } break; case MLE_CLASS_ROUTER: //Router and sleepy end device never do challenge default: challengeCheck = false; break; } if (challengeCheck) { if (cur->ttl > MLE_TABLE_CHALLENGE_TIMER || cur->ttl < MLE_TABLE_CHALLENGE_TIMER) { new_ttl = ticks + MLE_TABLE_CHALLENGE_TIMER; } if (cur->ttl <= new_ttl) { if (cur->ttl != 1) { if (mle_class_ptr->keep_alive_cb(mle_class_ptr->interfaceId, cur->mac64) != 0) { cur->ttl--; if (cur->ttl == 1) { remove_entry = true; } } else { cur->ttl = 1; //Lock retries here } } } else { cur->ttl -= ticks; } } else { if (ticks >= cur->ttl) { remove_entry = true; } else { cur->ttl -= ticks; } } if (remove_entry) { //Silence delete //Remove from list ns_list_remove(&mle_class_ptr->mle_table, cur); //Free Indirect Queue mle_table_remove_free_indirect_table(mle_class_ptr->interfaceId, cur); mle_class_ptr->remove_cb(mle_class_ptr->interfaceId, cur); topo_trace(TOPOLOGY_MLE, cur->ext64, TOPO_REMOVE); //Removes ETX neighbor etx_neighbor_remove(mle_class_ptr->interfaceId, cur); //Add to free list ns_list_add_to_start(&mle_class_ptr->free_enty_list, cur); } } // for each entry //Router to Router Challenge timeout for big network and FHSS systems which could loose broadcast messages. if (mle_class_ptr->challenge_cb && mle_class_ptr->mode == MLE_CLASS_ROUTER) { //Calculate timeout trigger uint8_t challenge_count = 0; ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_class_ptr->mle_table) { if (((cur->mode & MLE_DEV_MASK) == MLE_FFD_DEV) && !cur->medium_ttl_challenge) { //Challenge Neighbour if (cur->ttl < (cur->timeout_rx / 2)) { if (mle_class_ptr->challenge_cb(mle_class_ptr->interfaceId, cur->mac64) != 0) { tr_error("Router2Router challenge start fail"); return; } cur->medium_ttl_challenge = true; if (++challenge_count == 2) { //trig only 2 active / 4 second period. return; } } } } } } mle_neigh_table_list_t *mle_class_active_list_get(int8_t interface_id) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return NULL; } return &mle_class_ptr->mle_table; } uint16_t mle_class_active_neigh_counter(int8_t interface_id) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs if (!mle_class_ptr) { return 0xffff; } return ns_list_count(&mle_class_ptr->mle_table); } uint8_t *mle_general_write_source_address(uint8_t *ptr, protocol_interface_info_entry_t *cur) { if (cur->global_address_available) { uint16_t mac16 = mac_helper_mac16_address_get(cur); if (mac16 < 0xfffe) { ptr = mle_tlv_write_source_address(ptr, mac16); } } return ptr; } uint8_t *mle_general_write_link_layer_framecounter(uint8_t *ptr, protocol_interface_info_entry_t *cur) { uint32_t temp_counter; mac_helper_link_frame_counter_read(cur->id, &temp_counter); return mle_tlv_write_link_layer_framecount(ptr, temp_counter); } static void mle_event_handler(arm_event_s *event) { switch (event->event_type) { case ARM_MLE_INIT: tr_debug("MLE Tasklet Generated"); break; case ARM_MLE_TTL_TIMER: //Do list in future for each of mle user //Set here mle class ttl update ns_list_foreach_safe(mle_table_class_t, mle_clas_entry, &mle_table_calss_list) { mle_class_table_ttl(1, mle_clas_entry); } break; } } bool mle_neigh_entry_frame_counter_update(mle_neigh_table_entry_t *entry_temp, uint8_t *tlv_ptr, uint16_t tlv_length, protocol_interface_info_entry_t *cur, uint8_t key_id) { mle_tlv_info_t mle_tlv_info; uint32_t frame_counter; if (mle_tlv_option_discover(tlv_ptr, tlv_length, MLE_TYPE_LL_FRAME_COUNTER, &mle_tlv_info) != 4) { if (cur->mac_parameters->SecurityEnabled) { return false; } else { frame_counter = 0; } } else { frame_counter = common_read_32_bit(mle_tlv_info.dataPtr); } mac_helper_devicetable_set(entry_temp, cur, frame_counter, key_id, false); return true; } void mle_entry_timeout_update(mle_neigh_table_entry_t *entry_temp, uint32_t timeout_tlv) { if (timeout_tlv > 86400) { timeout_tlv = 86400; } else if (timeout_tlv == 0) { timeout_tlv = 500; } timeout_tlv /= MLE_TIMER_TICKS_SECONDS; timeout_tlv++; entry_temp->timeout_rx = timeout_tlv; mle_entry_timeout_refresh(entry_temp); } void mle_entry_timeout_refresh(mle_neigh_table_entry_t *entry_temp) { entry_temp->ttl = entry_temp->timeout_rx; entry_temp->last_contact_time = protocol_core_monotonic_time; entry_temp->medium_ttl_challenge = false; } static void mle_refresh_entry(mle_neigh_table_entry_t *neig_info, bool dataPollConfirmation) { if (!neig_info) { return; } if (!neig_info->handshakeReady) { tr_debug("refresh:Link Handshake not ready yet"); return; } neig_info->last_contact_time = protocol_core_monotonic_time; neig_info->medium_ttl_challenge = false; if (dataPollConfirmation) { if (neig_info->ttl > MLE_TABLE_CHALLENGE_TIMER) { neig_info->ttl = neig_info->timeout_rx; } } else { neig_info->ttl = neig_info->timeout_rx; } } mle_neigh_table_entry_t *mle_refresh_entry_timeout(int8_t interfaceId, const uint8_t *addressPtr, addrtype_t addressType, bool dataPollConfirmation) { mle_neigh_table_entry_t * neigh_info = mle_class_get_by_link_address(interfaceId, addressPtr, addressType); mle_refresh_entry(neigh_info, dataPollConfirmation); return neigh_info; } #endif /* NO_MLE */