Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mle.c Source File

mle.c

00001 /*
00002  * Copyright (c) 2013-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "nsconfig.h"
00019 #include "MLE/mle.h"
00020 
00021 #ifndef NO_MLE
00022 #include "ns_types.h"
00023 #include "eventOS_event.h"
00024 #include "eventOS_event_timer.h"
00025 #include "socket_api.h"
00026 #include "Core/include/socket.h"
00027 #include "nsdynmemLIB.h"
00028 #include "ns_trace.h"
00029 #include "string.h"
00030 #include "NWK_INTERFACE/Include/protocol.h"
00031 #include "Common_Protocols/udp.h"
00032 #include "6LoWPAN/Thread/thread_common.h"
00033 #include "6LoWPAN/Thread/thread_bootstrap.h"
00034 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
00035 #include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h"
00036 #include "platform/arm_hal_interrupt.h"
00037 #include "platform/topo_trace.h"
00038 #include "common_functions.h"
00039 #include "MLE/mle_tlv.h"
00040 #include "NWK_INTERFACE/Include/protocol_timer.h"
00041 #include "Common_Protocols/ipv6_constants.h"
00042 #include "Service_Libs/mle_service/mle_service_api.h"
00043 #include "Service_Libs/etx/etx.h"
00044 #include "6LoWPAN/MAC/mac_helper.h"
00045 #include "mac_api.h"
00046 #include "6LoWPAN/MAC/mac_data_poll.h"
00047 #include "6LoWPAN/lowpan_adaptation_interface.h"
00048 
00049 #define MLE_UNICAST_CHALLENGE_TIMEOUT 20
00050 
00051 #define TRACE_GROUP "mle"
00052 
00053 typedef enum {
00054     ARM_MLE_INIT = 0,
00055     ARM_MLE_TTL_TIMER
00056 } arm_mle_event_id_e;
00057 
00058 //MLE class structure
00059 typedef struct mle_table_class {
00060     int8_t interfaceId;
00061     mle_class_user_mode mode;
00062     mle_neigh_table_list_t mle_table;       //Active Entry
00063     mle_neigh_table_list_t free_enty_list;
00064     mle_neigh_table_entry_t *allocated_buffer;
00065     uint8_t buffer_size;
00066     mle_entry_user_entry_remove_notify *remove_cb;
00067     mle_entry_link_keep_alive *keep_alive_cb;
00068     mle_entry_link_keep_alive *challenge_cb;
00069     mle_entry_interface_activate *interface_is_active;
00070     ns_list_link_t link; /*!< List link entry */
00071 } mle_table_class_t;
00072 
00073 static NS_LIST_DEFINE(mle_table_calss_list, mle_table_class_t, link);
00074 
00075 static int8_t mle_tasklet_id = -1;
00076 
00077 static arm_event_storage_t *mle_class_timer_storage = NULL;
00078 
00079 static mle_neigh_table_entry_t *mle_class_neighbor_get(mle_neigh_table_list_t *mle_table, const uint8_t *address, addrtype_t type);
00080 static mle_neigh_table_entry_t *mle_class_get_free_entry(mle_neigh_table_list_t *mle_table);
00081 static bool mle_class_neighbor_validate(mle_neigh_table_list_t *mle_table, const mle_neigh_table_entry_t *entry);
00082 static void mle_event_handler(arm_event_s *event);
00083 
00084 
00085 static bool mle_table_timer_start(void)
00086 {
00087     if (!mle_class_timer_storage) {
00088 
00089         arm_event_s event = {
00090                 .receiver = mle_tasklet_id,
00091                 .sender = 0,
00092                 .event_id = 0,
00093                 .data_ptr = NULL,
00094                 .event_type = ARM_MLE_TTL_TIMER,
00095                 .priority = ARM_LIB_LOW_PRIORITY_EVENT,
00096         };
00097 
00098         mle_class_timer_storage  = eventOS_event_timer_request_every(&event, eventOS_event_timer_ms_to_ticks(MLE_TIMER_TICKS_MS));
00099         if (!mle_class_timer_storage) {
00100             tr_error("Mle timer start fail");
00101             return false;
00102         }
00103     }
00104 
00105     return true;
00106 }
00107 
00108 static void mle_table_timer_stop(void)
00109 {
00110     if (mle_class_timer_storage && ns_list_is_empty(&mle_table_calss_list)) {
00111         eventOS_cancel(mle_class_timer_storage);
00112         mle_class_timer_storage = NULL;
00113     }
00114 }
00115 
00116 
00117 static void mle_table_remove_free_indirect_table(int8_t interface_id, mle_neigh_table_entry_t *entry_ptr)
00118 {
00119     protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id);
00120     if (!cur_interface) {
00121         return;
00122     }
00123     //Free firts by defined short address
00124     if (entry_ptr->short_adr < 0xfffe) {
00125         uint8_t temp_address[2];
00126         common_write_16_bit(entry_ptr->short_adr, temp_address);
00127         lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT );
00128     }
00129     lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG );
00130 }
00131 
00132 static void mle_table_class_list_free(mle_table_class_t *mle_table_class) {
00133 
00134     ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_table_class->mle_table) {
00135         ns_list_remove(&mle_table_class->mle_table, cur);
00136         //Clean Indirect queue
00137         mle_table_remove_free_indirect_table(mle_table_class->interfaceId, cur);
00138         //Call Remove callback
00139         mle_table_class->remove_cb(mle_table_class->interfaceId, cur);
00140         //Removes ETX neighbor
00141         etx_neighbor_remove(mle_table_class->interfaceId, cur);
00142         ns_list_add_to_start(&mle_table_class->free_enty_list, cur);
00143     }
00144     topo_trace(TOPOLOGY_MLE, NULL, TOPO_CLEAR);
00145 }
00146 
00147 static void mle_table_class_free(mle_table_class_t *main_list)
00148 {
00149     ns_list_remove(&mle_table_calss_list, main_list);
00150     mle_table_class_list_free(main_list);
00151     //Free list buffer
00152     ns_dyn_mem_free(main_list->allocated_buffer);
00153     ns_dyn_mem_free(main_list);
00154     mle_table_timer_stop();
00155 }
00156 
00157 
00158 
00159 static int8_t mle_table_class_table_buffer_allocate(mle_table_class_t *mle_class, uint8_t list_size)
00160 {
00161     mle_neigh_table_entry_t *list_buffer = ns_dyn_mem_alloc(sizeof(mle_neigh_table_entry_t) * list_size);
00162     if (!list_buffer) {
00163         return -1;
00164     }
00165 
00166     mle_class->allocated_buffer = list_buffer; //Save storaged
00167     ns_list_init(&mle_class->free_enty_list);
00168     ns_list_init(&mle_class->mle_table);
00169     for (uint8_t i = 0; i< list_size; i++) {
00170         memset(list_buffer, 0, sizeof(mle_neigh_table_entry_t));
00171 
00172         list_buffer->attribute_index = i;
00173         //Add to list
00174         ns_list_add_to_end(&mle_class->free_enty_list,list_buffer);
00175         list_buffer++;
00176     }
00177     return 0;
00178 }
00179 
00180 
00181 static mle_table_class_t * mle_table_class_allocate(int8_t interfaceId, uint8_t list_size)
00182 {
00183     mle_table_class_t *newClass = ns_dyn_mem_alloc(sizeof(mle_table_class_t));
00184 
00185     if (newClass) {
00186         memset(newClass, 0, sizeof(mle_table_class_t));
00187         if (mle_table_class_table_buffer_allocate(newClass,list_size) != 0) {
00188             ns_dyn_mem_free(newClass);
00189             return NULL;
00190         }
00191         newClass->interfaceId = interfaceId;
00192         newClass->buffer_size = list_size;
00193     }
00194     return newClass;
00195 }
00196 
00197 static mle_table_class_t * mle_table_class_discover(int8_t interface_id) {
00198     ns_list_foreach(mle_table_class_t, cur_mle_class, &mle_table_calss_list) {
00199         if (cur_mle_class->interfaceId == interface_id) {
00200             return cur_mle_class;
00201         }
00202     }
00203     return NULL;
00204 }
00205 
00206 static int8_t mle_class_event_handler_init(void) {
00207     if (mle_tasklet_id == -1) {
00208         //GENERATE TASKLET
00209         mle_tasklet_id = eventOS_event_handler_create(&mle_event_handler, ARM_MLE_INIT);
00210 
00211     }
00212 
00213     return mle_tasklet_id;
00214 }
00215 
00216 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)
00217 {
00218     //Discover from the list
00219     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00220     //Clean list and set function pointer call backs
00221     if (mle_class_ptr) {
00222         mle_class_ptr->remove_cb = remove_cb;
00223         mle_class_ptr->keep_alive_cb = keep_alive_cb;
00224         mle_class_ptr->challenge_cb = NULL;
00225         mle_class_ptr->interface_is_active = interface_is_active;
00226         if (mle_class_ptr->buffer_size != table_size) { //Clean tabs only when table size is different
00227             mle_table_class_list_free(mle_class_ptr);
00228             ns_dyn_mem_free(mle_class_ptr->allocated_buffer);
00229             mle_class_ptr->allocated_buffer = NULL;
00230             //Reallocate
00231             if (mle_table_class_table_buffer_allocate(mle_class_ptr,table_size) != 0) {
00232                 ns_list_remove(&mle_table_calss_list, mle_class_ptr);
00233                 ns_dyn_mem_free(mle_class_ptr);
00234                 return -2;
00235             }
00236             mle_class_ptr->buffer_size = table_size;
00237         }
00238         return 0;
00239     }
00240 
00241     if (mle_class_event_handler_init() < 0) {
00242         return -2;
00243     }
00244 
00245     if (!mle_table_timer_start()) {
00246         return -2;
00247     }
00248 
00249     mle_class_ptr  = mle_table_class_allocate(interface_id, table_size);
00250     //Allocate new
00251     if (!mle_class_ptr) {
00252         return -2;
00253     }
00254 
00255     tr_debug("MLE service init size %d", table_size);
00256     mle_class_ptr->remove_cb = remove_cb;
00257     mle_class_ptr->keep_alive_cb = keep_alive_cb;
00258     mle_class_ptr->challenge_cb = NULL;
00259     mle_class_ptr->interface_is_active = interface_is_active;
00260     ns_list_add_to_end(&mle_table_calss_list, mle_class_ptr);
00261     return 0;
00262 
00263 }
00264 
00265 int8_t mle_class_router_challenge(int8_t interface_id,mle_entry_link_keep_alive *challenge_cb)
00266 {
00267     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00268     //Clean list and set function pointer call backs
00269     if (!mle_class_ptr) {
00270         return -1;
00271     }
00272     mle_class_ptr->challenge_cb = challenge_cb;
00273     return 0;
00274 }
00275 
00276 bool mle_class_exists_for_interface(int8_t interface_id) {
00277 
00278     if (mle_table_class_discover(interface_id)) {
00279         return true;
00280     }
00281 
00282     return false;
00283 }
00284 
00285 int8_t mle_class_deallocate(int8_t interface_id)
00286 {
00287     //Discover from the list
00288     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00289     //Clean list and set function pointer call backs
00290     if (!mle_class_ptr) {
00291         return -1;
00292     }
00293 
00294     mle_table_class_free(mle_class_ptr);
00295     return 0;
00296 
00297 }
00298 
00299 int8_t mle_class_list_clean(int8_t interface_id)
00300 {
00301     //Discover from the list
00302     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00303     //Clean list and set function pointer call backs
00304     if (!mle_class_ptr) {
00305         return -1;
00306     }
00307 
00308     mle_table_class_list_free(mle_class_ptr);
00309     return 0;
00310 
00311 }
00312 
00313 int8_t mle_class_mode_set(int8_t interface_id,mle_class_user_mode mode)
00314 {
00315     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00316     //Clean list and set function pointer call backs
00317     if (!mle_class_ptr) {
00318         return -1;
00319     }
00320     mle_class_ptr->mode = mode;
00321 
00322     return 0;
00323 }
00324 
00325 int8_t mle_class_set_new_key_pending(int8_t interface_id)
00326 {
00327     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00328 
00329     if (!mle_class_ptr) {
00330         return -1;
00331     }
00332 
00333     ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_class_ptr->mle_table) {
00334         cur->new_key_pending = true;
00335     }
00336 
00337     return 0;
00338 }
00339 
00340 int16_t mle_class_free_entry_count_get(int8_t interface_id)
00341 {
00342     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00343     //Clean list and set function pointer call backs
00344     if (!mle_class_ptr) {
00345         return 0;
00346     }
00347     return ns_list_count(&(mle_class_ptr->free_enty_list));
00348 
00349 }
00350 
00351 int16_t mle_class_sleepy_entry_count_get(int8_t interface_id)
00352 {
00353     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00354 
00355     if (!mle_class_ptr) {
00356         return 0;
00357     }
00358 
00359     uint16_t count = 0;
00360 
00361     ns_list_foreach(mle_neigh_table_entry_t, entry, &mle_class_ptr->mle_table) {
00362         if (!(entry->mode & MLE_RX_ON_IDLE)) {
00363             count++;
00364         }
00365     }
00366 
00367     return count;
00368 }
00369 
00370 int16_t mle_class_rfd_entry_count_get(int8_t interface_id)
00371 {
00372     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00373 
00374     if (!mle_class_ptr) {
00375         return 0;
00376     }
00377 
00378     uint16_t count = 0;
00379 
00380     ns_list_foreach(mle_neigh_table_entry_t, entry, &mle_class_ptr->mle_table) {
00381         if ((entry->mode & MLE_DEV_MASK) == MLE_RFD_DEV) {
00382             count++;
00383         }
00384     }
00385 
00386     return count;
00387 }
00388 
00389 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)
00390 {
00391     // Check it really is LL64 (not LL16)
00392 
00393     if (memcmp(ipv6Address, ADDR_LINK_LOCAL_PREFIX , 8) != 0) {
00394         return NULL;    //Mot Link Local Address
00395     }
00396 
00397     if (memcmp((ipv6Address + 8), ADDR_SHORT_ADR_SUFFIC , 6) == 0) {
00398         return NULL;
00399     }
00400     // map
00401     uint8_t temporary_mac64[8];
00402     memcpy(temporary_mac64, (ipv6Address + 8), 8);
00403     temporary_mac64[0] ^= 2;
00404 
00405     return mle_class_get_entry_by_mac64(interface_id, linkMargin, temporary_mac64, allocateNew, new_entry_allocated);
00406 }
00407 
00408 mle_neigh_table_entry_t *mle_class_discover_entry_by_ll64(int8_t interface_id, const uint8_t *ipv6Address)
00409 {
00410 
00411     // Check it really is LL64 (not LL16)
00412 
00413     if (memcmp(ipv6Address, ADDR_LINK_LOCAL_PREFIX , 8) != 0) {
00414         return NULL;    //Mot Link Local Address
00415     }
00416 
00417     if (memcmp((ipv6Address + 8), ADDR_SHORT_ADR_SUFFIC , 6) == 0) {
00418         return NULL;
00419     }
00420     // map
00421     uint8_t temporary_mac64[8];
00422     memcpy(temporary_mac64, (ipv6Address + 8), 8);
00423     temporary_mac64[0] ^= 2;
00424 
00425     return mle_class_get_by_link_address(interface_id, temporary_mac64, ADDR_802_15_4_LONG );
00426 }
00427 
00428 
00429 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)
00430 {
00431     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00432     //Clean list and set function pointer call backs
00433     if (!mle_class_ptr) {
00434         return NULL;
00435     }
00436 
00437     if (new_entry_allocated) {
00438         *new_entry_allocated = false;
00439     }
00440 
00441     mle_neigh_table_entry_t *ret_val = mle_class_neighbor_get(&mle_class_ptr->mle_table, mac64, ADDR_802_15_4_LONG );
00442 
00443 
00444     /* Look for existing entry */
00445     if (ret_val) {
00446         ret_val->link_margin = ret_val->link_margin + linkMargin - (ret_val->link_margin >> THREAD_LINK_MARGIN_SCALING);
00447         return ret_val;
00448     }
00449 
00450     if (allocateNew) {
00451         ret_val = mle_class_get_free_entry(&mle_class_ptr->free_enty_list);
00452 
00453         if (ret_val) {
00454             //Add to active list
00455             ns_list_add_to_start(&mle_class_ptr->mle_table, ret_val);
00456             topo_trace(TOPOLOGY_MLE, mac64, TOPO_ADD);
00457             ret_val->link_margin = linkMargin << THREAD_LINK_MARGIN_SCALING;
00458             memcpy(ret_val->mac64, mac64, 8);
00459             if (new_entry_allocated) {
00460                 *new_entry_allocated = true;
00461             }
00462         }
00463     }
00464     return ret_val;
00465 }
00466 
00467 static mle_neigh_table_entry_t *mle_class_neighbor_get_by_attribute_index(mle_neigh_table_list_t *mle_table, uint8_t attribute_index)
00468 {
00469 
00470     ns_list_foreach(mle_neigh_table_entry_t, cur, mle_table) {
00471         if (cur->attribute_index == attribute_index) {
00472             return cur;
00473         }
00474     }
00475     return NULL;
00476 }
00477 
00478 static bool mle_class_neighbor_validate(mle_neigh_table_list_t *mle_table, const mle_neigh_table_entry_t *entry)
00479 {
00480 
00481     ns_list_foreach(mle_neigh_table_entry_t, cur, mle_table) {
00482         if (cur == entry) {
00483             return true;
00484         }
00485     }
00486     return false;
00487 }
00488 
00489 static mle_neigh_table_entry_t *mle_class_neighbor_get(mle_neigh_table_list_t *mle_table, const uint8_t *address, addrtype_t type)
00490 {
00491     uint16_t short_id;
00492     if (type == ADDR_802_15_4_SHORT ) {
00493         short_id = common_read_16_bit(address);
00494     }
00495     ns_list_foreach(mle_neigh_table_entry_t, cur, mle_table) {
00496 
00497         if (type == ADDR_802_15_4_SHORT ) {
00498             if (cur->short_adr == short_id) {
00499                 return cur;
00500             }
00501         } else  {
00502             if (memcmp(cur->mac64, address, 8) == 0) {
00503                 return cur;
00504             }
00505         }
00506 
00507     }
00508     return NULL;
00509 }
00510 
00511 static mle_neigh_table_entry_t *mle_class_get_free_entry(mle_neigh_table_list_t *mle_table)
00512 {
00513     mle_neigh_table_entry_t *mle_entry = ns_list_get_first(mle_table);
00514     if (mle_entry) {
00515         //Remove from the list
00516         ns_list_remove(mle_table, mle_entry);
00517         uint8_t attribute_id = mle_entry->attribute_index;
00518         memset(mle_entry, 0, sizeof(mle_neigh_table_entry_t));
00519         mle_entry->attribute_index = attribute_id;
00520         mle_entry->short_adr = 0xffff;
00521         mle_entry->mode = MLE_FFD_DEV | MLE_RX_ON_IDLE;
00522         mle_entry->holdTime = 7;
00523         mle_entry->last_contact_time = protocol_core_monotonic_time;
00524         mle_entry->mle_frame_counter = 0;
00525         mle_entry->last_key_sequence = 0;
00526         mle_entry->new_key_pending = false;
00527         mle_entry->medium_ttl_challenge = false;
00528     }
00529 
00530     return mle_entry;
00531 }
00532 
00533 
00534 
00535 mle_neigh_table_entry_t *mle_class_get_by_link_address(int8_t interface_id, const uint8_t *address, addrtype_t type)
00536 {
00537     switch (type) {
00538         case ADDR_802_15_4_SHORT :
00539         case ADDR_802_15_4_LONG :
00540 
00541             break;
00542         default:
00543             return NULL;
00544     }
00545 
00546     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00547     //Clean list and set function pointer call backs
00548     if (!mle_class_ptr) {
00549         return NULL;
00550     }
00551 
00552     return mle_class_neighbor_get(&mle_class_ptr->mle_table, address, type);
00553 
00554 }
00555 
00556 mle_neigh_table_entry_t *mle_class_get_by_device_attribute_id(int8_t interface_id, uint8_t attribute_index)
00557 {
00558     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00559     //Clean list and set function pointer call backs
00560     if (!mle_class_ptr) {
00561         return NULL;
00562     }
00563 
00564     return mle_class_neighbor_get_by_attribute_index(&mle_class_ptr->mle_table, attribute_index);
00565 
00566 }
00567 
00568 int8_t mle_class_remove_entry(int8_t interface_id, mle_neigh_table_entry_t *entry)
00569 {
00570     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00571     //Clean list and set function pointer call backs
00572     if (!mle_class_ptr) {
00573         return -1;
00574     }
00575 
00576     //Validate Pointer
00577     if (!mle_class_neighbor_validate(&mle_class_ptr->mle_table, entry)) {
00578         return -2;
00579     }
00580     //Remove from list
00581     ns_list_remove(&mle_class_ptr->mle_table, entry);
00582     //Free Indirect Queue
00583     mle_table_remove_free_indirect_table(mle_class_ptr->interfaceId, entry);
00584     //Call Remove callback
00585     mle_class_ptr->remove_cb(mle_class_ptr->interfaceId, entry);
00586     topo_trace(TOPOLOGY_MLE, entry->ext64, TOPO_REMOVE);
00587 
00588     //Removes ETX neighbor
00589     etx_neighbor_remove(interface_id, entry);
00590     //Add to free list
00591     ns_list_add_to_start(&mle_class_ptr->free_enty_list, entry);
00592     return 0;
00593 }
00594 
00595 int8_t mle_class_remove_neighbour(int8_t interface_id, const uint8_t *address, addrtype_t type)
00596 {
00597     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00598     //Clean list and set function pointer call backs
00599     if (!mle_class_ptr) {
00600         return -1;
00601     }
00602 
00603     mle_neigh_table_entry_t * entry = mle_class_get_by_link_address(interface_id, address, type);
00604     if (!entry) {
00605         return -2;
00606     }
00607     //Remove from list
00608     ns_list_remove(&mle_class_ptr->mle_table, entry);
00609     //Free Indirect Queue
00610     mle_table_remove_free_indirect_table(mle_class_ptr->interfaceId, entry);
00611     //Call Remove callback
00612     mle_class_ptr->remove_cb(mle_class_ptr->interfaceId, entry);
00613 
00614     topo_trace(TOPOLOGY_MLE, entry->ext64, TOPO_REMOVE);
00615 
00616      //Removes ETX neighbor
00617      etx_neighbor_remove(interface_id, entry);
00618     //Add to free list
00619     ns_list_add_to_start(&mle_class_ptr->free_enty_list, entry);
00620 
00621     return 0;
00622 
00623 }
00624 
00625 
00626 
00627 static void mle_class_table_ttl(uint16_t ticks, mle_table_class_t *mle_class_ptr)
00628 {
00629     uint16_t new_ttl;
00630     bool challengeCheck;
00631     bool remove_entry;
00632 
00633     //validate that interface is still active
00634     if (!mle_class_ptr->interface_is_active(mle_class_ptr->interfaceId)) {
00635         return;
00636     }
00637 
00638     ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_class_ptr->mle_table) {
00639         new_ttl = 0;
00640         remove_entry = false;
00641         switch (mle_class_ptr->mode) {
00642             case MLE_CLASS_END_DEVICE:
00643                 if (cur->priorityFlag) {
00644                     challengeCheck = true;
00645                 } else {
00646                     challengeCheck = false;
00647                 }
00648                 break;
00649             case MLE_CLASS_ROUTER: //Router and sleepy end device never do challenge
00650             default:
00651                 challengeCheck = false;
00652                 break;
00653         }
00654 
00655         if (challengeCheck) {
00656             if (cur->ttl > MLE_TABLE_CHALLENGE_TIMER || cur->ttl < MLE_TABLE_CHALLENGE_TIMER) {
00657                 new_ttl = ticks + MLE_TABLE_CHALLENGE_TIMER;
00658             }
00659 
00660             if (cur->ttl <= new_ttl) {
00661                 if (cur->ttl != 1) {
00662                     if (mle_class_ptr->keep_alive_cb(mle_class_ptr->interfaceId, cur->mac64) != 0) {
00663                         cur->ttl--;
00664                         if (cur->ttl == 1) {
00665                             remove_entry = true;
00666                         }
00667                     } else {
00668                         cur->ttl = 1; //Lock retries here
00669                     }
00670                 }
00671             } else {
00672                 cur->ttl -= ticks;
00673             }
00674         } else {
00675             if (ticks >= cur->ttl) {
00676 
00677                 remove_entry = true;
00678             } else {
00679                 cur->ttl -= ticks;
00680             }
00681         }
00682 
00683         if (remove_entry) {
00684             //Silence delete
00685             //Remove from list
00686             ns_list_remove(&mle_class_ptr->mle_table, cur);
00687             //Free Indirect Queue
00688             mle_table_remove_free_indirect_table(mle_class_ptr->interfaceId, cur);
00689             mle_class_ptr->remove_cb(mle_class_ptr->interfaceId, cur);
00690             topo_trace(TOPOLOGY_MLE, cur->ext64, TOPO_REMOVE);
00691             //Removes ETX neighbor
00692             etx_neighbor_remove(mle_class_ptr->interfaceId, cur);
00693             //Add to free list
00694             ns_list_add_to_start(&mle_class_ptr->free_enty_list, cur);
00695 
00696         }
00697     } // for each entry
00698 
00699     //Router to Router Challenge timeout for big network and FHSS systems which could loose broadcast messages.
00700     if (mle_class_ptr->challenge_cb && mle_class_ptr->mode == MLE_CLASS_ROUTER) {
00701         //Calculate timeout trigger
00702         uint8_t challenge_count = 0;
00703         ns_list_foreach_safe(mle_neigh_table_entry_t, cur, &mle_class_ptr->mle_table) {
00704             if (((cur->mode & MLE_DEV_MASK) == MLE_FFD_DEV)  && !cur->medium_ttl_challenge) {
00705                 //Challenge Neighbour
00706                 if (cur->ttl < (cur->timeout_rx / 2)) {
00707                     if (mle_class_ptr->challenge_cb(mle_class_ptr->interfaceId, cur->mac64) != 0) {
00708                         tr_error("Router2Router challenge start fail");
00709                         return;
00710                     }
00711                     cur->medium_ttl_challenge = true;
00712                     if (++challenge_count == 2) {
00713                         //trig only 2 active / 4 second period.
00714                         return;
00715                     }
00716                 }
00717             }
00718         }
00719     }
00720 }
00721 
00722 
00723 mle_neigh_table_list_t *mle_class_active_list_get(int8_t interface_id)
00724 {
00725     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00726     //Clean list and set function pointer call backs
00727     if (!mle_class_ptr) {
00728         return NULL;
00729     }
00730     return &mle_class_ptr->mle_table;
00731 }
00732 
00733 uint16_t mle_class_active_neigh_counter(int8_t interface_id)
00734 {
00735     mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id);
00736     //Clean list and set function pointer call backs
00737     if (!mle_class_ptr) {
00738         return 0xffff;
00739     }
00740 
00741 
00742     return ns_list_count(&mle_class_ptr->mle_table);
00743 }
00744 
00745 uint8_t *mle_general_write_source_address(uint8_t *ptr, protocol_interface_info_entry_t *cur)
00746 {
00747     if (cur->global_address_available) {
00748         uint16_t mac16 = mac_helper_mac16_address_get(cur);
00749         if (mac16 < 0xfffe) {
00750             ptr = mle_tlv_write_source_address(ptr, mac16);
00751         }
00752     }
00753     return ptr;
00754 }
00755 
00756 uint8_t *mle_general_write_link_layer_framecounter(uint8_t *ptr, protocol_interface_info_entry_t *cur)
00757 {
00758     uint32_t temp_counter;
00759     mac_helper_link_frame_counter_read(cur->id, &temp_counter);
00760     return mle_tlv_write_link_layer_framecount(ptr, temp_counter);
00761 }
00762 
00763 static void mle_event_handler(arm_event_s *event)
00764 {
00765     switch (event->event_type) {
00766         case ARM_MLE_INIT:
00767             tr_debug("MLE Tasklet Generated");
00768             break;
00769 
00770         case ARM_MLE_TTL_TIMER:
00771             //Do list in future for each of mle user
00772             //Set here mle class ttl update
00773             ns_list_foreach_safe(mle_table_class_t, mle_clas_entry, &mle_table_calss_list) {
00774                 mle_class_table_ttl(1, mle_clas_entry);
00775             }
00776 
00777 
00778             break;
00779     }
00780 }
00781 
00782 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)
00783 {
00784     mle_tlv_info_t mle_tlv_info;
00785     uint32_t frame_counter;
00786     if (mle_tlv_option_discover(tlv_ptr, tlv_length, MLE_TYPE_LL_FRAME_COUNTER, &mle_tlv_info)  != 4) {
00787         if (cur->mac_parameters->SecurityEnabled) {
00788             return false;
00789         } else {
00790             frame_counter = 0;
00791         }
00792     } else {
00793         frame_counter = common_read_32_bit(mle_tlv_info.dataPtr);
00794     }
00795 
00796     mac_helper_devicetable_set(entry_temp, cur, frame_counter, key_id, false);
00797     return true;
00798 }
00799 
00800 void mle_entry_timeout_update(mle_neigh_table_entry_t *entry_temp, uint32_t timeout_tlv)
00801 {
00802     if (timeout_tlv > 86400) {
00803         timeout_tlv = 86400;
00804     } else if (timeout_tlv == 0) {
00805         timeout_tlv = 500;
00806     }
00807     timeout_tlv /= MLE_TIMER_TICKS_SECONDS;
00808     timeout_tlv++;
00809     entry_temp->timeout_rx = timeout_tlv;
00810     mle_entry_timeout_refresh(entry_temp);
00811 }
00812 
00813 void mle_entry_timeout_refresh(mle_neigh_table_entry_t *entry_temp)
00814 {
00815     entry_temp->ttl = entry_temp->timeout_rx;
00816     entry_temp->last_contact_time = protocol_core_monotonic_time;
00817     entry_temp->medium_ttl_challenge = false;
00818 }
00819 
00820 static void mle_refresh_entry(mle_neigh_table_entry_t *neig_info, bool dataPollConfirmation)
00821 {
00822     if (!neig_info) {
00823         return;
00824     }
00825     if (!neig_info->handshakeReady) {
00826         tr_debug("refresh:Link Handshake not ready yet");
00827         return;
00828     }
00829 
00830     neig_info->last_contact_time = protocol_core_monotonic_time;
00831     neig_info->medium_ttl_challenge = false;
00832 
00833     if (dataPollConfirmation) {
00834         if (neig_info->ttl > MLE_TABLE_CHALLENGE_TIMER) {
00835             neig_info->ttl = neig_info->timeout_rx;
00836         }
00837     } else {
00838         neig_info->ttl = neig_info->timeout_rx;
00839     }
00840 }
00841 
00842 mle_neigh_table_entry_t *mle_refresh_entry_timeout(int8_t interfaceId, const uint8_t *addressPtr, addrtype_t addressType, bool dataPollConfirmation)
00843 {
00844     mle_neigh_table_entry_t * neigh_info =  mle_class_get_by_link_address(interfaceId, addressPtr, addressType);
00845     mle_refresh_entry(neigh_info, dataPollConfirmation);
00846     return neigh_info;
00847 }
00848 
00849 #endif /* NO_MLE */