Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nd_router_object.c Source File

nd_router_object.c

00001 /*
00002  * Copyright (c) 2013-2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "nsconfig.h"
00018 #ifdef HAVE_6LOWPAN_ND
00019 #include "ns_types.h"
00020 #include "string.h"
00021 #include "nsdynmemLIB.h"
00022 #include "ns_trace.h"
00023 #include "NWK_INTERFACE/Include/protocol.h"
00024 #include "Common_Protocols/icmpv6.h"
00025 #include "Common_Protocols/icmpv6_prefix.h"
00026 #include "Common_Protocols/icmpv6_radv.h"
00027 #include "randLIB.h"
00028 #ifdef HAVE_RPL
00029 #include "RPL/rpl_control.h"
00030 #include "RPL/rpl_data.h"
00031 #endif
00032 #include "MLE/mle.h"
00033 #include "6LoWPAN/IPHC_Decode/cipv6.h"
00034 #include "6LoWPAN/ND/nd_router_object.h"
00035 #include "6LoWPAN/Bootstraps/network_lib.h"
00036 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
00037 #include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h"
00038 #include "6LoWPAN/MAC/mac_helper.h"
00039 #include "Service_Libs/whiteboard/whiteboard.h"
00040 #include "common_functions.h"
00041 #include "BorderRouter/border_router.h"
00042 #include "Service_Libs/pan_blacklist/pan_blacklist_api.h"
00043 #include "6LoWPAN/MAC/mac_data_poll.h"
00044 #include "6LoWPAN/ws/ws_common.h"
00045 #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
00046 
00047 #define TRACE_GROUP "loND"
00048 
00049 void icmp_nd_router_object_release(nd_router_t *router_object);
00050 uint8_t icmp_nd_router_prefix_ttl_update(nd_router_t *nd_router_object, protocol_interface_info_entry_t *cur_interface, uint16_t seconds);
00051 static uint8_t nd_router_bootstrap_timer(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint16_t ticks);
00052 #ifdef HAVE_RPL
00053 static void nd_ra_build(nd_router_t *cur, const uint8_t *address, protocol_interface_info_entry_t *cur_interface);
00054 static void nd_ns_forward_timer_reset(uint8_t *root_adr);
00055 static void nd_router_forward_timer(nd_router_t *cur, uint16_t ticks_update);
00056 static nd_router_t *nd_router_object_scan_by_prefix(const uint8_t *prefix, nwk_interface_id nwk_id);
00057 #else
00058 #define nd_ra_build(cur, address, cur_interface) ((void)0)
00059 #define nd_ns_forward_timer_reset(root_adr) ((void)0)
00060 #define nd_router_forward_timer(root_adr, ticks_update) ((void)0)
00061 #define nd_router_object_scan_by_prefix(prefix, nwk_id) NULL
00062 #endif
00063 
00064 static void lowpan_nd_address_cb(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason);
00065 uint8_t nd_rs_build(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface);
00066 bool icmp_nd_compare_to_def_next_hop(nd_router_next_hop *hop, sockaddr_t *adr);
00067 void icmp_nd_router_context_ttl_update(nd_router_t *nd_router_object, uint16_t seconds);
00068 
00069 //ND Router List
00070 static NS_LARGE NS_LIST_DEFINE(nd_router_list, nd_router_t, link);
00071 
00072 /*
00073  * Default values are documented in net_6lowpan_parameter_api.h - keep in sync.
00074  */
00075 uint8_t nd_base_tick = 1;
00076 
00077 nd_parameters_s nd_params = {
00078     .rs_retry_max = 3,
00079     .rs_retry_interval_min = 15,
00080     .ns_retry_interval_min = 100,
00081     .ns_retry_linear_backoff = 100,
00082     .timer_random_max = 31,
00083     .ns_retry_max = 5,
00084     .multihop_dad = true,
00085     .iids_map_to_mac = false,
00086     .send_nud_probes = true,
00087     .ra_interval_min = 160,
00088     .ra_transmits = 3,
00089     .ra_cur_hop_limit = ADV_CUR_HOP_LIMIT,
00090     .ra_link_mtu = 0,
00091     .ra_reachable_time = 0,
00092     .ra_retrans_timer = 0,
00093     .ns_forward_timeout = 300,
00094 };
00095 
00096 #ifdef HAVE_6LOWPAN_BORDER_ROUTER
00097 int8_t nd_set_br(nd_router_t *br)
00098 {
00099     if (ns_list_is_empty(&nd_router_list)) {
00100         ns_list_add_to_start(&nd_router_list, br);
00101         return 0;
00102     }
00103     return -1;
00104 }
00105 #endif
00106 
00107 bool nd_object_active(void)
00108 {
00109     if (!ns_list_is_empty(&nd_router_list)) {
00110         return true;
00111     }
00112     return false;
00113 }
00114 
00115 void icmp_nd_routers_init(void)
00116 {
00117     ns_list_foreach_safe(nd_router_t, cur, &nd_router_list) {
00118         ns_list_remove(&nd_router_list, cur);
00119         icmp_nd_router_object_release(cur);
00120     }
00121 }
00122 
00123 
00124 void icmp_nd_set_nd_def_router_address(uint8_t *ptr, nd_router_t *cur)
00125 {
00126     memcpy(ptr, ADDR_LINK_LOCAL_PREFIX, 8);
00127     ptr += 8;
00128     if (cur->default_hop.addrtype == ADDR_802_15_4_SHORT ) {
00129         memcpy(ptr, ADDR_SHORT_ADR_SUFFIC, 6);
00130         ptr += 6;
00131         *ptr++ = cur->default_hop.address[0];
00132         *ptr = cur->default_hop.address[1];
00133     } else {
00134         memcpy(ptr, cur->default_hop.address, 8);
00135     }
00136 }
00137 
00138 void nd_ns_trig(nd_router_t *router_object, protocol_interface_info_entry_t *cur)
00139 {
00140     //
00141     ns_list_foreach(prefix_entry_t, prefix, &router_object->prefix_list) {
00142         if (prefix->options & PIO_A) {
00143             ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) {
00144                 if (e->source == ADDR_SOURCE_SLAAC && (memcmp(e->address, prefix->prefix, 8) == 0)) {
00145                     if (cur->if_6lowpan_dad_process.active) {
00146                         e->state_timer = 5;
00147                     } else {
00148                         e->state_timer = 25;
00149                         cur->if_6lowpan_dad_process.active = true;
00150                         memcpy(cur->if_6lowpan_dad_process.address, e->address, 16);
00151                         cur->if_6lowpan_dad_process.count = nd_params.ns_retry_max;
00152                     }
00153                 }
00154             }
00155         }
00156     }
00157 }
00158 
00159 void nd_router_base_init(nd_router_t *new_entry)
00160 {
00161     ns_list_link_init(new_entry, link);
00162     new_entry->nd_timer = 0;
00163     new_entry->nd_bootstrap_tick = 0;
00164     new_entry->nd_re_validate = 0;
00165     new_entry->mle_advert_timer = 0;
00166     new_entry->mle_purge_timer = 0;
00167     new_entry->default_hop.addrtype = ADDR_NONE ;
00168     ns_list_init(&new_entry->prefix_list);
00169     ns_list_init(&new_entry->context_list);
00170     new_entry->secondaty_hop = 0;
00171     new_entry->ns_forward_timer = 0;
00172     new_entry->flags = 0;
00173     new_entry->ra_timing.initial_rtr_adv_count = 0;
00174     new_entry->ra_timing.rtr_adv_last_send_time = protocol_core_monotonic_time - 0x10000;
00175     new_entry->abro_version_num = 0;
00176     new_entry->trig_address_reg = false;
00177 }
00178 
00179 static void nd_router_remove(nd_router_t *router, protocol_interface_info_entry_t *interface)
00180 {
00181     tr_debug("route remove");
00182     icmpv6_stop_router_advertisements(interface, router->border_router);
00183     ns_list_remove(&nd_router_list, router);
00184     icmp_nd_router_object_release(router);
00185 
00186     if (ns_list_is_empty(&nd_router_list)) {
00187         arm_6lowpan_bootstrap_init(interface);
00188     }
00189 }
00190 
00191 nd_router_t *icmp_nd_router_object_get(const uint8_t *border_router, nwk_interface_id nwk_id)
00192 {
00193     nd_router_t *new_entry = 0;
00194     uint_fast8_t count = 0;
00195 
00196     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
00197         if (cur->nd_state == ND_BR_READY) {
00198             return NULL;
00199         }
00200         if (cur->nwk_id == nwk_id) {
00201             if (memcmp(cur->border_router, border_router, 16) == 0) {
00202                 return cur;
00203             }
00204         }
00205         ++count;
00206     }
00207 
00208     if (count >= ND_OBJECT_MAX) {
00209         return NULL;
00210     }
00211 
00212     new_entry = ns_dyn_mem_alloc(sizeof(nd_router_t));
00213     if (!new_entry) {
00214         tr_error("No heap for New Border Router");
00215         return NULL;
00216     }
00217 
00218     new_entry->nd_state = ND_READY;
00219     new_entry->nwk_id = nwk_id;
00220     nd_router_base_init(new_entry);
00221     memcpy(new_entry->border_router, border_router, 16);
00222     new_entry->trig_address_reg = false;
00223     ns_list_add_to_end(&nd_router_list, new_entry);
00224 
00225     return new_entry;
00226 }
00227 
00228 void icmp_nd_router_object_reset(nd_router_t *router_object)
00229 {
00230     icmpv6_prefix_list_free(&router_object->prefix_list);
00231 
00232     lowpan_context_list_free(&router_object->context_list);
00233 
00234     if (router_object->secondaty_hop) {
00235         ns_dyn_mem_free(router_object->secondaty_hop);
00236         router_object->secondaty_hop = 0;
00237     }
00238 }
00239 #ifdef HAVE_6LOWPAN_BORDER_ROUTER
00240 int8_t icmp_nd_router_prefix_proxy_update(uint8_t *dptr, nd_router_setup_t *nd_router_object)
00241 {
00242     prefix_entry_t *new_entry = 0;
00243     uint8_t pre_setups;
00244     uint32_t lifeTime, prefTime;
00245     uint8_t prefix_len = *dptr++;
00246     pre_setups = *dptr++;
00247     lifeTime = common_read_32_bit(dptr);
00248     dptr += 4;
00249     prefTime = common_read_32_bit(dptr);
00250     dptr += 4;
00251     pre_setups |= PIO_R;
00252 
00253     new_entry = icmpv6_prefix_add(&nd_router_object->prefix_list, dptr, prefix_len, lifeTime, prefTime, pre_setups);
00254     if (new_entry) {
00255         new_entry->options = pre_setups;
00256         return 0;
00257     }
00258     return -2;
00259 }
00260 #endif
00261 
00262 uint8_t icmp_nd_router_prefix_valid(nd_router_t *nd_router_object)
00263 {
00264     ns_list_foreach(prefix_entry_t, cur, &nd_router_object->prefix_list) {
00265         if ((cur->options & PIO_A) && cur->lifetime) {
00266             return 1;
00267         }
00268     }
00269     return 0;
00270 }
00271 
00272 /* Returns 1 if the router object has been removed */
00273 uint8_t icmp_nd_router_prefix_ttl_update(nd_router_t *nd_router_object, protocol_interface_info_entry_t *cur_interface, uint16_t seconds)
00274 {
00275     ns_list_foreach(prefix_entry_t, cur, &nd_router_object->prefix_list) {
00276         if (cur->preftime != 0xffffffff && cur->preftime) {
00277             if (cur->preftime <=  seconds) {
00278                 tr_warn("PREFTIME zero");
00279                 cur->preftime = 0;
00280             } else {
00281                 cur->preftime -= seconds;
00282             }
00283 
00284         }
00285 
00286         if (cur->lifetime != 0xffffffff && cur->lifetime) {
00287             if (cur->lifetime > seconds) {
00288                 cur->lifetime -= seconds;
00289             } else {
00290                 tr_debug("Prefix Expiry");
00291                 if (nd_router_object->nd_state != ND_BR_READY) {
00292                     if (cur->options & PIO_A) {
00293                         tr_debug("Delete GP Address by Prefix, start RS");
00294                         nd_router_remove(nd_router_object, cur_interface);
00295                         return 1;
00296                     }
00297                 }
00298             }
00299         }
00300     }
00301 
00302     return 0;
00303 }
00304 
00305 static int icmp_nd_slaac_prefix_address_gen(protocol_interface_info_entry_t *cur_interface, uint8_t *prefix, uint8_t prefix_len, uint32_t lifetime, uint32_t preftime, bool borRouterDevice, slaac_src_e slaac_src)
00306 {
00307     if_address_entry_t *address_entry = NULL;
00308     address_entry = icmpv6_slaac_address_add(cur_interface, prefix, prefix_len, lifetime, preftime, true, slaac_src);
00309     if (address_entry) {
00310         //Set Callback
00311         address_entry->cb = lowpan_nd_address_cb;
00312         if (borRouterDevice) {
00313             address_entry->state_timer = 0;
00314         } else {
00315             address_entry->state_timer = 45 + randLIB_get_random_in_range(1, nd_params.timer_random_max);
00316             //Allocate Addres registration state
00317             if (cur_interface->if_6lowpan_dad_process.active == false) {
00318                 cur_interface->if_6lowpan_dad_process.count = nd_params.ns_retry_max;
00319                 cur_interface->if_6lowpan_dad_process.active = true;
00320                 memcpy(cur_interface->if_6lowpan_dad_process.address, address_entry->address, 16);
00321             }
00322 
00323             if ((cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) && cur_interface->nwk_bootstrap_state == ER_SCAN) {
00324                 cur_interface->nwk_bootstrap_state = ER_ADDRESS_REQ;
00325                 cur_interface->bootsrap_state_machine_cnt = 0;
00326             }
00327         }
00328         return 0;
00329     }
00330     return -1;
00331 }
00332 
00333 
00334 static void lowpan_nd_address_cb(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason)
00335 {
00336     nd_router_t *cur = NULL;
00337     bool g16_address;
00338     tr_debug("Interface ID: %i, ipv6: %s", interface->id, trace_ipv6(addr->address));
00339 
00340     if (memcmp(&addr->address[8], ADDR_SHORT_ADR_SUFFIC, 6) == 0) {
00341         g16_address = true;
00342     } else {
00343         g16_address = false;
00344     }
00345 
00346     switch (reason) {
00347         case ADDR_CALLBACK_DAD_COMPLETE:
00348             if (addr_ipv6_equal(interface->if_6lowpan_dad_process.address, addr->address)) {
00349                 tr_info("Address REG OK: %s", trace_ipv6(interface->if_6lowpan_dad_process.address));
00350                 interface->if_6lowpan_dad_process.active = false;
00351                 interface->global_address_available = true;
00352                 //Check If GP16 Address Add LL16 Address
00353                 if (interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) {
00354                     if (g16_address) {
00355                         //Register also GP64 if NET_6LOWPAN_MULTI_GP_ADDRESS mode is enabled
00356                         if (interface->lowpan_address_mode == NET_6LOWPAN_MULTI_GP_ADDRESS) {
00357                             if (icmp_nd_slaac_prefix_address_gen(interface, addr->address, addr->prefix_len,
00358                                                                  addr->valid_lifetime, addr->preferred_lifetime, false, SLAAC_IID_DEFAULT) == 0) {
00359                                 return;
00360                             } else {
00361                                 tr_warning("Secondary Address allocate fail");
00362                             }
00363                         }
00364 
00365                     }
00366 
00367                     protocol_6lowpan_bootstrap_nd_ready(interface);
00368                 } else {
00369                     //Disable protocol poll
00370                     mac_data_poll_protocol_poll_mode_decrement(interface);
00371                 }
00372 
00373             }
00374             break;
00375 
00376         case ADDR_CALLBACK_TIMER:
00377             tr_debug("State Timer CB");
00378             if (interface->if_6lowpan_dad_process.active) {
00379                 if (memcmp(addr->address, interface->if_6lowpan_dad_process.address, 16) == 0) {
00380                     cur = nd_get_object_by_nwk_id(interface->nwk_id);
00381                 } else {
00382                     addr->state_timer = 5;
00383                 }
00384             } else {
00385                 cur = nd_get_object_by_nwk_id(interface->nwk_id);
00386                 if (cur) {
00387                     interface->if_6lowpan_dad_process.count = nd_params.ns_retry_max;
00388                     interface->if_6lowpan_dad_process.active = true;
00389                     memcpy(interface->if_6lowpan_dad_process.address, addr->address, 16);
00390                 } else {
00391                     tr_debug("No ND Object for Address");
00392                 }
00393             }
00394 
00395             if (cur) {
00396                 if (interface->if_6lowpan_dad_process.count) {
00397                     nd_ns_build(cur, interface, addr->address);
00398                     addr->state_timer = nd_params.ns_retry_interval_min;
00399                     addr->state_timer += nd_params.ns_retry_linear_backoff * (nd_params.ns_retry_max - interface->if_6lowpan_dad_process.count);
00400                     addr->state_timer += (randLIB_get_16bit() & nd_params.timer_random_max);
00401                     tr_debug("NS Configured");
00402                     interface->if_6lowpan_dad_process.count--;
00403                     //Enable Protocol Poll mode
00404                     if (interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
00405                         mac_data_poll_init_protocol_poll(interface);
00406                     }
00407                 } else {
00408 
00409                     //ND FAIL
00410                     tr_error("NS Fail");
00411                     protocol_6lowpan_neighbor_remove(interface, cur->default_hop.address, cur->default_hop.addrtype);
00412 
00413                     if (cur->secondaty_hop) {
00414                         tr_warn("Try Secondary Route");
00415                         memcpy(&cur->default_hop, cur->secondaty_hop, sizeof(nd_router_next_hop));
00416                         ns_dyn_mem_free(cur->secondaty_hop);
00417                         cur->secondaty_hop = 0;
00418                         interface->if_6lowpan_dad_process.count = nd_params.ns_retry_max;
00419                         addr->state_timer = 1;
00420                     } else {
00421                         interface->if_6lowpan_dad_process.active = false;
00422                         protocol_6lowpan_nd_borderrouter_connection_down(interface);
00423                     }
00424                 }
00425             }
00426 
00427             break;
00428 
00429         case ADDR_CALLBACK_PARENT_FULL:
00430             interface->if_6lowpan_dad_process.count = 0;
00431             tr_error("ND cache full--> Black list by given lifetime");
00432             cur = nd_get_object_by_nwk_id(interface->nwk_id);
00433             if (cur) {
00434                 pan_blacklist_pan_set(&interface->pan_blaclist_cache, mac_helper_panid_get(interface), cur->life_time);
00435             }
00436             break;
00437 
00438         case ADDR_CALLBACK_DAD_FAILED:
00439             if (g16_address) {
00440                 tr_warn("ARO Failure:Duplicate address");
00441                 uint16_t shortAddress = common_read_16_bit(&addr->address[14]);
00442                 tr_warn("Del old ll16");
00443                 protocol_6lowpan_del_ll16(interface, shortAddress);
00444                 //Check if Application not freeze new address allocartion
00445                 if (interface->reallocate_short_address_if_duplicate) {
00446 
00447                     protocol_6lowpan_allocate_mac16(interface);
00448                     interface->if_6lowpan_dad_process.active = false;
00449                     if (icmp_nd_slaac_prefix_address_gen(interface, addr->address, addr->prefix_len,
00450                                                          addr->valid_lifetime, addr->preferred_lifetime, false, SLAAC_IID_6LOWPAN_SHORT) == 0) {
00451                         addr->state_timer = 1;
00452                         return;
00453                     }
00454                 }
00455             }
00456             bootsrap_next_state_kick(ER_BOOTSTRAP_DAD_FAIL, interface);
00457 
00458             break;
00459 
00460         default:
00461             break;
00462     }
00463 }
00464 
00465 int8_t icmp_nd_router_prefix_update(uint8_t *dptr, nd_router_t *nd_router_object, protocol_interface_info_entry_t *cur_interface)
00466 {
00467     slaac_src_e slaac_src;
00468     bool borRouterDevice;
00469     prefix_entry_t *new_entry = 0;
00470     uint8_t prefix_len = *dptr++;
00471     uint8_t pre_setups = *dptr++;
00472     uint32_t lifetime = common_read_32_bit(dptr);
00473     uint32_t preftime = common_read_32_bit(dptr + 4);
00474 
00475     if (cur_interface->lowpan_address_mode == NET_6LOWPAN_GP16_ADDRESS
00476             || cur_interface->lowpan_address_mode == NET_6LOWPAN_MULTI_GP_ADDRESS) {
00477         slaac_src = SLAAC_IID_6LOWPAN_SHORT;
00478     } else {
00479         slaac_src = SLAAC_IID_DEFAULT;
00480     }
00481     if (cur_interface->border_router_setup) {
00482         borRouterDevice = true;
00483     } else {
00484         borRouterDevice = false;
00485     }
00486 
00487     //Read Lifetimes + skip resertved 4 bytes
00488     dptr += 12;
00489     new_entry = icmpv6_prefix_add(&nd_router_object->prefix_list, dptr, prefix_len, lifetime, preftime, pre_setups);
00490     if (new_entry) {
00491         if (new_entry->options == 0xff) {
00492             new_entry->options = pre_setups;
00493             if (new_entry->options & PIO_A) {
00494                 if (icmpv6_slaac_prefix_update(cur_interface, new_entry->prefix, new_entry->prefix_len, new_entry->lifetime, new_entry->preftime) != 0) {
00495                     icmp_nd_slaac_prefix_address_gen(cur_interface, new_entry->prefix, new_entry->prefix_len, new_entry->lifetime, new_entry->preftime, borRouterDevice, slaac_src);
00496                 }
00497             }
00498         } else {
00499             icmpv6_slaac_prefix_update(cur_interface, dptr, prefix_len, lifetime, preftime);
00500         }
00501 
00502         if (nd_router_object->trig_address_reg) {
00503             nd_router_object->trig_address_reg = false;
00504             icmpv6_slaac_prefix_register_trig(cur_interface, dptr, prefix_len);
00505         }
00506 
00507         return 0;
00508     }
00509 
00510     return -2;
00511 }
00512 
00513 /* Update lifetime and expire contexts in ABRO storage */
00514 void icmp_nd_router_context_ttl_update(nd_router_t *nd_router_object, uint16_t seconds)
00515 {
00516     ns_list_foreach_safe(lowpan_context_t, cur, &nd_router_object->context_list) {
00517         /* We're using seconds in call, but lifetime is in 100ms ticks */
00518         if (cur->lifetime <= (uint32_t)seconds * 10) {
00519             /* When lifetime in the ABRO storage runs out, just drop it,
00520              * so we stop advertising it. This is different from the
00521              * interface context handling.
00522              */
00523             ns_list_remove(&nd_router_object->context_list, cur);
00524             ns_dyn_mem_free(cur);
00525         } else {
00526             cur->lifetime -= (uint32_t)seconds * 10;
00527         }
00528     }
00529 }
00530 
00531 void icmp_nd_router_object_release(nd_router_t *router_object)
00532 {
00533     if (router_object) {
00534         icmp_nd_router_object_reset(router_object);
00535         ns_dyn_mem_free(router_object);
00536     }
00537 }
00538 
00539 
00540 void icmp_nd_border_router_release(nd_router_t *router_object)
00541 {
00542     if (router_object) {
00543         if (!ns_list_is_empty(&nd_router_list)) {
00544             ns_list_remove(&nd_router_list, router_object);
00545         }
00546         icmp_nd_router_object_reset(router_object);
00547     }
00548 }
00549 
00550 
00551 
00552 void gp_address_list_free(gp_ipv6_address_list_t *list)
00553 {
00554     ns_list_foreach_safe(gp_ipv6_address_entry_t, cur, list) {
00555         ns_list_remove(list, cur);
00556         ns_dyn_mem_free(cur);
00557     }
00558 }
00559 
00560 /*
00561  * Parse 6LoWPAN Context Options (RFC 6775 4.2) for ABRO storage.
00562  *
00563  *     0                   1                   2                   3
00564  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00565  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00566  * |     Type      |     Length    |Context Length | Res |C|  CID  |
00567  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00568  * |            Reserved           |         Valid Lifetime        |
00569  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00570  * .                                                               .
00571  * .                       Context Prefix                          .
00572  * .                                                               .
00573  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00574  *
00575  */
00576 static void icmp_nd_context_parse(buffer_t *buf, nd_router_t *nd_router_object)
00577 {
00578     const uint8_t *dptr = buffer_data_pointer(buf);
00579     uint16_t data_len = buffer_data_length(buf);
00580     uint16_t read = 0;
00581 
00582     while (read < data_len) {
00583         uint8_t type = dptr[0];
00584         uint16_t len = dptr[1] * 8;
00585 
00586         read += len;
00587 
00588         if (len == 0 || read > data_len) {
00589             return;
00590         } else if (type == ICMPV6_OPT_6LOWPAN_CONTEXT) {
00591             uint8_t ctx_len = dptr[2];
00592 
00593             if ((len == 16 && ctx_len <= 64) || (len == 24 && ctx_len <= 128)) {
00594                 uint8_t c_id = dptr[3] & 0x1f; // ignore reserved fields
00595                 uint16_t lifetime_mins = common_read_16_bit(dptr + 6);
00596 
00597                 lowpan_context_update(&nd_router_object->context_list, c_id, lifetime_mins, dptr + 8, ctx_len, true);
00598             } else {
00599                 tr_warn("Context len fail");
00600             }
00601         }
00602         dptr += len;
00603     }
00604 }
00605 
00606 void icmp_nd_prefixs_parse(buffer_t *buf, nd_router_t *nd_router_object, protocol_interface_info_entry_t *cur_interface)
00607 {
00608     uint8_t *dptr;
00609     uint16_t data_len = buffer_data_length(buf);
00610     uint16_t readed = 0;
00611     uint8_t type, len;
00612     dptr = buffer_data_pointer(buf);
00613     while (readed  < data_len) {
00614         type = *dptr++;
00615         len  = *dptr++;
00616         if (len == 0) {
00617             return;
00618         }
00619         len <<= 3;
00620         readed += len;
00621 
00622         if (readed > data_len) {
00623             return;
00624         } else if (type == ICMPV6_OPT_PREFIX_INFO && len == 32) {
00625             icmp_nd_router_prefix_update(dptr, nd_router_object, cur_interface);
00626             dptr += 30;
00627         } else {
00628             dptr += (len - 2);
00629         }
00630     }
00631 }
00632 
00633 
00634 void icmp_nd_set_next_hop(nd_router_next_hop *hop, sockaddr_t *adr)
00635 {
00636     uint8_t *ptr = 0;
00637     ptr = hop->address;
00638     if (adr->addr_type  == ADDR_IPV6 ) {
00639         if (memcmp(&adr->address [8], ADDR_SHORT_ADR_SUFFIC, 6) == 0) {
00640             hop->addrtype = ADDR_802_15_4_SHORT ;
00641             memcpy(ptr, &adr->address [14], 2);
00642         } else {
00643             hop->addrtype = ADDR_802_15_4_LONG ;
00644             memcpy(ptr, &adr->address [8], 8);
00645         }
00646     } else {
00647         hop->addrtype = adr->addr_type ;
00648         memcpy(ptr, &adr->address [2], 8);
00649     }
00650 }
00651 
00652 bool icmp_nd_compare_to_def_next_hop(nd_router_next_hop *hop, sockaddr_t *adr)
00653 {
00654     if (adr->addr_type  == ADDR_IPV6 ) {
00655         if (memcmp(&adr->address [8], ADDR_SHORT_ADR_SUFFIC, 6) == 0) {
00656             if (hop->addrtype == ADDR_802_15_4_SHORT ) {
00657                 if (memcmp(hop->address, &adr->address [14], 2) == 0) {
00658                     return false;
00659                 }
00660             }
00661         } else {
00662             if (hop->addrtype == ADDR_802_15_4_LONG ) {
00663                 if (memcmp(hop->address, &adr->address [8], 8) == 0) {
00664                     return false;
00665                 }
00666             }
00667 
00668         }
00669     } else {
00670         hop->addrtype = adr->addr_type ;
00671         memcpy(hop->address, &adr->address [2], 8);
00672     }
00673     return true;
00674 }
00675 
00676 uint8_t nd_rs_build(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface)
00677 {
00678     buffer_t *buf;
00679 
00680     if (cur) {
00681         uint8_t dest_addr[16];
00682         icmp_nd_set_nd_def_router_address(dest_addr, cur);
00683         buf = icmpv6_build_rs(cur_interface, dest_addr);
00684     } else {
00685         buf = icmpv6_build_rs(cur_interface, NULL);
00686     }
00687 
00688     if (buf) {
00689         arm_net_protocol_packet_handler(buf, cur_interface);
00690         return 1;
00691     }
00692     return 0;
00693 }
00694 
00695 #ifdef HAVE_RPL
00696 static bool rpl_parents_only(const ipv6_route_info_t *route, bool valid)
00697 {
00698     return valid && rpl_data_is_rpl_parent_route(route->source);
00699 }
00700 #endif
00701 
00702 /* Neighbor Solicitation (RFC4861) with Address Registration Option (RFC6775)
00703  * and Source Link-Layer Address Option (RFC4861)
00704  */
00705 void nd_ns_build(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint8_t *address_ptr)
00706 {
00707     uint8_t router[16];
00708     aro_t aro;
00709     buffer_t *buf;
00710 
00711 #ifdef HAVE_RPL
00712     /* If we're a host, we will just send to our ND parent. But as a router,
00713      * we don't really maintain our ND parent - send NA instead to the RPL
00714      * parent we would use to talk to the border router.
00715      */
00716     if ((cur_interface->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) && cur_interface->rpl_domain) {
00717         ipv6_route_t *route = ipv6_route_choose_next_hop(cur->border_router, cur_interface->id, rpl_parents_only);
00718         if (!route) {
00719             /* Important to return 1 so this counts as a "success" - caller then backs off due to lack of response and time out */
00720             return;
00721         }
00722         memcpy(router, route->info.next_hop_addr, 16);
00723     } else
00724 #endif
00725     {
00726         icmp_nd_set_nd_def_router_address(router, cur);
00727     }
00728 
00729     aro.status = ARO_SUCCESS;
00730     aro.present = true;
00731     aro.lifetime = (cur->life_time / 60) + 1;
00732     memcpy(aro.eui64, cur_interface->mac, 8);
00733 
00734     buf = icmpv6_build_ns(cur_interface, router, address_ptr, true, false, &aro);
00735     protocol_push(buf);
00736 }
00737 
00738 /* RFC 6775 Duplicate Address Request/Confirmation packets
00739  *
00740  *     0                   1                   2                   3
00741  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00742  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00743  * |     Type      |     Code      |          Checksum             |
00744  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00745  * |    Status     |   Reserved    |     Registration Lifetime     |
00746  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00747  * |                                                               |
00748  * +                            EUI-64                             +
00749  * |                                                               |
00750  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00751  * |                                                               |
00752  * +                                                               +
00753  * |                                                               |
00754  * +                       Registered Address                      +
00755  * |                                                               |
00756  * +                                                               +
00757  * |                                                               |
00758  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00759  *
00760  * (and 8.2.1 implies this is can be followed by options, although
00761  * none are defined).
00762  */
00763 #ifdef HAVE_6LOWPAN_ROUTER
00764 static bool nd_dar_dac_valid(buffer_t *buf)
00765 {
00766     const uint8_t *dptr = buffer_data_pointer(buf);
00767 
00768     if (buf->options .code  != 0) {
00769         return false;
00770     }
00771 
00772     if (!icmpv6_options_well_formed_in_buffer(buf, 28)) {
00773         return false;
00774     }
00775 
00776     if (addr_is_ipv6_multicast(dptr + 12)) {
00777         return false;
00778     }
00779 
00780     if (addr_is_ipv6_unspecified(buf->src_sa .address ) ||
00781             addr_is_ipv6_multicast(buf->src_sa .address )) {
00782         return false;
00783     }
00784 
00785     return true;
00786 }
00787 #endif
00788 
00789 buffer_t *nd_dar_parse(buffer_t *buf, protocol_interface_info_entry_t *cur_interface)
00790 {
00791 #if defined WHITEBOARD && defined HAVE_6LOWPAN_BORDER_ROUTER
00792     uint8_t *dptr = buffer_data_pointer(buf);
00793     buffer_t *retbuf;
00794     uint8_t status;
00795     uint16_t lifetime;
00796     const uint8_t *eui64;
00797 
00798     if (!nd_dar_dac_valid(buf)) {
00799         goto drop;
00800     }
00801 
00802     status = *dptr;
00803     dptr += 2;
00804     lifetime = common_read_16_bit(dptr);
00805     dptr += 2;
00806 
00807     if (status != ARO_SUCCESS) {
00808         goto drop;
00809     }
00810 
00811     whiteboard_entry_t *wb;
00812 
00813     /* EUI-64 */
00814     eui64 = dptr;
00815     dptr += 8;
00816     tr_debug("DAR adr: %s, from %s", trace_ipv6(dptr), trace_ipv6(buf->src_sa .address ));
00817 
00818     //SET White board
00819     wb = whiteboard_table_update(dptr, eui64, &status);
00820     if (wb && status == ARO_SUCCESS) {
00821         memcpy(wb->address, dptr, 16);
00822         memcpy(wb->eui64, eui64, 8);
00823         wb->interface_index = cur_interface->id;
00824         wb->ttl = UINT24_C(60) * lifetime;
00825     }
00826 
00827     retbuf = icmpv6_build_dad(cur_interface, NULL, ICMPV6_TYPE_INFO_DAC, buf->src_sa .address , eui64, dptr, status, lifetime);
00828     if (retbuf) {
00829         buffer_free(buf);
00830         return retbuf;
00831     }
00832 
00833 drop:
00834 #else
00835     (void)cur_interface;
00836 #endif
00837 
00838     return buffer_free(buf);
00839 }
00840 
00841 #ifdef HAVE_6LOWPAN_ROUTER
00842 static void nd_update_registration(protocol_interface_info_entry_t *cur_interface, ipv6_neighbour_t *neigh, const aro_t *aro)
00843 {
00844     /* We are about to send an ARO response - update our Neighbour Cache accordingly */
00845     if (aro->status == ARO_SUCCESS && aro->lifetime != 0) {
00846         neigh->type = IP_NEIGHBOUR_REGISTERED;
00847         neigh->lifetime = aro->lifetime * UINT32_C(60);
00848         ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00849         /* Register with 2 seconds off the lifetime - don't want the NCE to expire before the route */
00850         ipv6_route_add_metric(neigh->ip_address, 128, cur_interface->id, neigh->ip_address, ROUTE_ARO, NULL, 0, neigh->lifetime - 2, 32);
00851 
00852         /* We need to know peer is a host before publishing - this needs MLE. Not yet established
00853          * what to do without MLE - might need special external/non-external prioritisation at root.
00854          * This "publish for RFD" rule comes from ZigBee IP.
00855          */
00856         mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur_interface), ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh), ADDR_802_15_4_LONG );
00857 
00858         if (entry) {
00859             if (ws_info(cur_interface)) {
00860                 ws_common_etx_validate(cur_interface, entry);
00861             }
00862 
00863             if (!entry->ffd_device ) {
00864                 rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime);
00865             }
00866         }
00867         protocol_6lowpan_neighbor_address_state_synch(cur_interface, aro->eui64, neigh->ip_address + 8);
00868 
00869     } else {
00870         /* Um, no - can't transmit response if we remove NCE now! */
00871         //ipv6_neighbour_entry_remove(&cur_interface->ipv6_neighbour_cache, neigh);
00872         neigh->type = IP_NEIGHBOUR_TENTATIVE;
00873         neigh->lifetime = 2;
00874         ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00875         ipv6_route_add_metric(neigh->ip_address, 128, cur_interface->id, neigh->ip_address, ROUTE_ARO, NULL, 0, 4, 32);
00876         rpl_control_unpublish_address(protocol_6lowpan_rpl_domain, neigh->ip_address);
00877     }
00878 }
00879 
00880 void nd_remove_registration(protocol_interface_info_entry_t *cur_interface, addrtype_t ll_type, const uint8_t *ll_address)
00881 {
00882     ns_list_foreach_safe(ipv6_neighbour_t, cur, &cur_interface->ipv6_neighbour_cache.list) {
00883         if ((cur->type == IP_NEIGHBOUR_REGISTERED
00884                 || cur->type == IP_NEIGHBOUR_TENTATIVE)
00885                 && ipv6_neighbour_ll_addr_match(cur, ll_type, ll_address)) {
00886 
00887             ipv6_route_delete(cur->ip_address, 128, cur_interface->id, cur->ip_address,
00888                               ROUTE_ARO);
00889             ipv6_neighbour_entry_remove(&cur_interface->ipv6_neighbour_cache,
00890                                         cur);
00891         }
00892     }
00893 }
00894 
00895 /* Process ICMP Neighbor Solicitation (RFC 4861 + RFC 6775) ARO. */
00896 bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uint8_t *aro_opt, const uint8_t *slla_opt, const uint8_t *src_addr, aro_t *aro_out)
00897 {
00898     /* Ignore any ARO if source is link-local */
00899     if (addr_is_ipv6_link_local(src_addr)) {
00900         return true; /* Transmit NA, without ARO */
00901     }
00902 
00903     /* If we can't parse the SLLAO, then act as if no SLLAO: ignore ARO */
00904     sockaddr_t ll_addr;
00905     if (!cur_interface->if_llao_parse(cur_interface, slla_opt, &ll_addr)) {
00906         return true; /* Transmit NA, without ARO */
00907     }
00908 
00909     /*
00910      *  0                   1                   2                   3
00911      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00912      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00913      * |   Type = 33   |   Length = 2  |    Status     |   Reserved    |
00914      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00915      * |           Reserved            |     Registration Lifetime     |
00916      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00917      * |                                                               |
00918      * +                            EUI-64                             +
00919      * |                                                               |
00920      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00921      */
00922     /* icmpv6_ns_handler has already checked incoming status == 0 */
00923     aro_out->lifetime = common_read_16_bit(aro_opt + 6);
00924     memcpy(aro_out->eui64, aro_opt + 8, 8);
00925 
00926     /* Check if we are already using this address ourself */
00927     if (addr_interface_address_compare(cur_interface, src_addr) == 0) {
00928         aro_out->present = true;
00929         aro_out->status = ARO_DUPLICATE;
00930         return true;
00931     }
00932 
00933     /* TODO - check hard upper limit on registrations? */
00934     if (ws_info(cur_interface) &&
00935             !ws_common_allow_child_registration(cur_interface, aro_out->eui64)) {
00936         aro_out->present = true;
00937         aro_out->status = ARO_FULL;
00938         return true;
00939     }
00940 
00941     /* We need to have entry in the Neighbour Cache */
00942     ipv6_neighbour_t *neigh = ipv6_neighbour_lookup_or_create(&cur_interface->ipv6_neighbour_cache, src_addr);
00943     if (!neigh) {
00944         aro_out->present = true;
00945         aro_out->status = ARO_FULL;
00946         return true;
00947     }
00948 
00949     uint8_t *nce_eui64 = ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh);
00950     if (neigh->state != IP_NEIGHBOUR_NEW) {
00951         switch (neigh->type) {
00952             case IP_NEIGHBOUR_TENTATIVE:
00953                 /* Is zero EUI-64 still possible? */
00954                 if (memcmp(nce_eui64, aro_out->eui64, 8) && memcmp(nce_eui64, ADDR_EUI64_ZERO, 8)) {
00955                     /* Have a Tentative NCE with different EUI-64 - ignore NS; two
00956                      * people trying to register at once. One should retry.
00957                      */
00958                     return false;
00959                 }
00960                 break;
00961             case IP_NEIGHBOUR_REGISTERED:
00962                 if (memcmp(nce_eui64, aro_out->eui64, 8)) {
00963                     /* Already registered with different EUI-64 - duplicate */
00964                     aro_out->present = true;
00965                     aro_out->status = ARO_DUPLICATE;
00966                     return true;
00967                 }
00968                 break;
00969             case IP_NEIGHBOUR_GARBAGE_COLLECTIBLE:
00970                 break;
00971         }
00972     }
00973 
00974     if (neigh->type != IP_NEIGHBOUR_REGISTERED) {
00975         neigh->type = IP_NEIGHBOUR_TENTATIVE;
00976         neigh->lifetime = TENTATIVE_NCE_LIFETIME;
00977         memcpy(nce_eui64, aro_out->eui64, 8);
00978     }
00979 
00980     /* Set the LL address, ensure it's marked STALE */
00981     ipv6_neighbour_entry_update_unsolicited(&cur_interface->ipv6_neighbour_cache, neigh, ll_addr.addr_type , ll_addr.address );
00982     ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00983     if (ws_info(cur_interface)) {
00984         aro_out->status = ARO_SUCCESS;
00985         aro_out->present = true;
00986         // Todo: this might not be needed...
00987         nd_update_registration(cur_interface, neigh, aro_out);
00988         return true;
00989     }
00990     if (cur_interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || nd_params.multihop_dad == false) {
00991         if (cur_interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
00992             whiteboard_entry_t *wb;
00993             wb = whiteboard_table_update(src_addr, aro_out->eui64, &aro_out->status);
00994             if (wb) {
00995                 if (aro_out->status == ARO_SUCCESS) {
00996                     memcpy(wb->address, src_addr, 16);
00997                     memcpy(wb->eui64, aro_out->eui64, 8);
00998                     wb->interface_index = cur_interface->id;
00999                     wb->ttl = 50000;//life_time;
01000                 }
01001             } else {
01002                 tr_warn("white Board Registry fail");
01003                 aro_out->status = ARO_FULL;
01004                 goto RESPONSE;
01005             }
01006         }
01007 
01008 RESPONSE:
01009         aro_out->present = true;
01010         nd_update_registration(cur_interface, neigh, aro_out);
01011         return true; /* Transmit NA */
01012     } else { /* Non-border router and multihop DAD: relay as DAR to Border Router */
01013         nd_router_t *nd_router_obj = 0;
01014 
01015         nd_router_obj = nd_router_object_scan_by_prefix(src_addr, cur_interface->nwk_id);
01016         if (!nd_router_obj) {
01017             /* Don't know where to send this. Do we say "yay" or "nay"? */
01018             /* For now, ignore ARO, as with old code; don't set aro_out.present */
01019             return true;
01020         }
01021 
01022         buffer_t *buf = icmpv6_build_dad(cur_interface, NULL, ICMPV6_TYPE_INFO_DAR, nd_router_obj->border_router, aro_out->eui64, src_addr, 0, aro_out->lifetime);
01023         if (!buf) {
01024             return false;    /* Failed to build DAR - drop NS */
01025         }
01026 
01027         tr_debug("RX:NS --> TX DAR to Root");
01028         protocol_push(buf);
01029         if (nd_router_obj->ns_forward_timer == 0) {
01030             nd_router_obj->ns_forward_timer = nd_params.ns_forward_timeout;
01031         }
01032 
01033         return false; /* Tell ns_handler to not transmit now */
01034     }
01035 }
01036 
01037 buffer_t *nd_dac_handler(buffer_t *buf, protocol_interface_info_entry_t *cur)
01038 {
01039     uint8_t *dptr, target_address[16], *reg_address;
01040     aro_t aro;
01041 
01042     dptr = buffer_data_pointer(buf);
01043 
01044     if (!nd_dar_dac_valid(buf)) {
01045         return buffer_free(buf);
01046     }
01047 
01048     nd_ns_forward_timer_reset(buf->src_sa .address );
01049 
01050     aro.status  = *dptr;
01051     dptr += 2;
01052     aro.lifetime = common_read_16_bit(dptr);
01053     dptr += 2;
01054     /* EUI-64 */
01055     memcpy(aro.eui64, dptr, 8);
01056     dptr += 8;
01057     reg_address = dptr;
01058     dptr += 16;
01059 
01060     ipv6_neighbour_t *neigh = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, reg_address);
01061     if (!neigh || neigh->type == IP_NEIGHBOUR_GARBAGE_COLLECTIBLE || memcmp(ipv6_neighbour_eui64(&cur->ipv6_neighbour_cache, neigh), aro.eui64, 8)) {
01062         return buffer_free(buf);
01063     }
01064 
01065     nd_update_registration(cur, neigh, &aro);
01066 
01067     /* RFC 6775 has a bit of a hole here - what's the Target Address? */
01068     /* It's not in the DAC. We didn't record locally when we sent the DAR */
01069     /* I guess it's logical that we use a link-local address. We break */
01070     /* RFC 4861 by responding "solicited", but not to the NS Target... */
01071     /* However, my reading of RFC 4861 says that the receiver should do */
01072     /* the right thing. Only problem is that what if they really did want */
01073     /* to do a NUD probe for our GP addr, but included the ARO by mistake? */
01074     if (addr_interface_get_ll_address(cur, target_address, 0)) {
01075         return buffer_free(buf);
01076     }
01077 
01078     /* NA builder will send it to the address in the buffer's source */
01079     memcpy(buf->src_sa .address , reg_address, 16);
01080 
01081     buffer_t *na_buf = icmpv6_build_na(cur, true, true, false, target_address, &aro, buf->src_sa .address );
01082 
01083     buffer_free(buf);
01084 
01085     return na_buf;
01086 }
01087 #endif // HAVE_6LOWPAN_ROUTER
01088 
01089 /* Original ABRO-based all-in-one parser. This needs some rework to separate ABRO-related and unrelated bits */
01090 /* Returns "false" if ABRO suggested it was a stale message, so not worth handling in the normal code */
01091 bool nd_ra_process_abro(protocol_interface_info_entry_t *cur, buffer_t *buf, const uint8_t *dptr, uint8_t ra_flags, uint16_t router_lifetime)
01092 {
01093     nd_router_t *router;
01094     uint32_t abro_ver_num;
01095     uint16_t temp16;
01096     bool uptodate = false;
01097 
01098     /* XXX this is really a 32-bit number these days */
01099     temp16 = common_read_16_bit(dptr);
01100     abro_ver_num = temp16;
01101     dptr += 2;
01102     temp16 = common_read_16_bit(dptr);
01103     //SET MSB bytes to 32-bit
01104     abro_ver_num |= ((uint32_t)temp16 << 16);
01105 
01106     dptr += 4;
01107     //If Border Router boot is state
01108 
01109     if (cur->border_router_setup) {
01110         if (memcmp(dptr, cur->border_router_setup->border_router_gp_adr, 16) == 0) {
01111             if (cur->border_router_setup->initActive) {
01112                 //save New Context
01113                 if (common_serial_number_greater_32(abro_ver_num, cur->border_router_setup->nd_border_router_configure->abro_version_num)) {
01114                     cur->border_router_setup->initActive = false;
01115                     cur->border_router_setup->nd_border_router_configure->abro_version_num = (abro_ver_num + 0x00010000);
01116                     cur->border_router_setup->nd_nwk->abro_version_num = (abro_ver_num + 0x00010000);
01117                 } else if (abro_ver_num == cur->border_router_setup->nd_border_router_configure->abro_version_num) {
01118 
01119                     cur->border_router_setup->initActive = false;
01120                     cur->border_router_setup->nd_border_router_configure->abro_version_num = (abro_ver_num + 0x00010000);
01121                     cur->border_router_setup->nd_nwk->abro_version_num = (abro_ver_num + 0x00010000);
01122                 }
01123             }
01124             return true;
01125         }
01126         return false;
01127     }
01128 
01129     router = icmp_nd_router_object_get(dptr, buf->interface ->nwk_id);
01130     if (!router) {
01131         return true;
01132     }
01133 
01134     if (router->default_hop.addrtype == ADDR_NONE ) {
01135         tr_debug("Create ND version");
01136 
01137         router->flags = ra_flags;
01138 
01139         uptodate = true;
01140         icmp_nd_set_next_hop(&router->default_hop, &buf->src_sa );
01141         router->default_hop.LQI = buf->options .lqi ;
01142 
01143         icmp_nd_prefixs_parse(buf, router, cur);
01144         icmp_nd_context_parse(buf, router);
01145 
01146         if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01147             //SET OnlY primary
01148             uint8_t address[8];
01149             if (router->default_hop.addrtype == ADDR_802_15_4_SHORT ) {
01150                 address[6] = router->default_hop.address[0];
01151                 address[7] = router->default_hop.address[1];
01152                 memcpy(address, ADDR_SHORT_ADR_SUFFIC, 6);
01153             } else {
01154                 memcpy(address, router->default_hop.address, 8);
01155             }
01156             protocol_6lowpan_neighbor_priority_update(cur, NULL, address);
01157         }
01158         router->nd_state = ND_READY;
01159         router->nd_re_validate = (router_lifetime / 5) * 4;
01160         router->nd_timer = 10;
01161     } else {
01162         bool new_router = icmp_nd_compare_to_def_next_hop(&router->default_hop, &buf->src_sa );
01163 
01164         if (abro_ver_num == router->abro_version_num) {
01165             /* Up-to-date for host processing, but don't necessarily process for multi-hop relaying */
01166             uptodate = true;
01167         }
01168 
01169         /* XXX this is really a 32-bit number these days */
01170         if (common_serial_number_greater_32(abro_ver_num, router->abro_version_num)) {
01171             uint32_t diff_update;
01172             diff_update = (abro_ver_num - router->abro_version_num);
01173             uptodate = true;
01174 
01175             //uprouter_info=1;
01176             if (diff_update >= 0x00010000) {
01177                 tr_debug("Border Router Boot Trig NS");
01178                 router->trig_address_reg = true;
01179             } else {
01180                 tr_debug("Next num");
01181             }
01182 
01183             icmpv6_prefix_list_free(&router->prefix_list);
01184 
01185             lowpan_context_list_free(&router->context_list);
01186 
01187             icmp_nd_prefixs_parse(buf, router, cur);
01188             router->trig_address_reg = false;
01189             icmp_nd_context_parse(buf, router);
01190             icmpv6_restart_router_advertisements(cur, router->border_router);
01191         } else if (router->default_hop.LQI < buf->options .lqi ) {
01192             /* XXX another zero-hysteresis parent swap */
01193             if (new_router) {
01194                 uint8_t *sec_ptr = NULL;
01195                 if (router->secondaty_hop == 0) {
01196                     router->secondaty_hop = ns_dyn_mem_alloc(sizeof(nd_router_next_hop));
01197                 } else {
01198                     nd_router_next_hop *hop = router->secondaty_hop;
01199                     sec_ptr = hop->address;
01200                     if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01201                         if (hop->addrtype == ADDR_802_15_4_SHORT ) {
01202                             hop->address[6] = hop->address[0];
01203                             hop->address[7] = hop->address[1];
01204                             memcpy(hop->address, ADDR_SHORT_ADR_SUFFIC, 6);
01205                         }
01206                     }
01207                 }
01208                 if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01209                     //Remove old secondary priority and set new primary
01210                     protocol_6lowpan_neighbor_priority_update(cur, sec_ptr, &buf->src_sa .address [8]);
01211                 }
01212                 //
01213                 if (router->secondaty_hop) {
01214                     memcpy(router->secondaty_hop, &router->default_hop, sizeof(nd_router_next_hop));
01215                 }
01216                 icmp_nd_set_next_hop(&router->default_hop, &buf->src_sa );
01217             }
01218             router->default_hop.LQI = buf->options .lqi ;
01219         } else if (new_router) {
01220             if (!router->secondaty_hop) {
01221                 router->secondaty_hop = ns_dyn_mem_alloc(sizeof(nd_router_next_hop));
01222                 if (router->secondaty_hop) {
01223                     router->secondaty_hop->LQI = 0;
01224                 }
01225             }
01226             if (router->secondaty_hop) {
01227                 if (router->secondaty_hop->LQI < buf->options .lqi ) {
01228                     icmp_nd_set_next_hop(router->secondaty_hop, &buf->src_sa );
01229                     router->secondaty_hop->LQI = buf->options .lqi ;
01230                     if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01231                         //SET only new primary
01232                         protocol_6lowpan_neighbor_priority_update(cur, 0, &buf->src_sa .address [8]);
01233                     }
01234                 }
01235             }
01236         }
01237         /* If waiting for an RS response */
01238         /* XXX this accepts it even if stale - no abro version check. Problem? */
01239         /* XXX this section below smells like stuff that should be outside this function */
01240         if (router->nd_state == ND_RS_UNCAST || router->nd_state == ND_RS_MULTICAST) {
01241             /* Set uptodate to true so we accept data into our interface tables.
01242              * Consistent with previous behaviour, but is this what we want?
01243              */
01244             uptodate = true;
01245             router->flags = ra_flags;
01246             icmp_nd_set_next_hop(&router->default_hop, &buf->src_sa );
01247             router->default_hop.LQI = buf->options .lqi ;
01248 
01249             icmp_nd_prefixs_parse(buf, router, cur);
01250             icmp_nd_context_parse(buf, router);
01251 
01252             if (router->nd_state == ND_RS_MULTICAST) {
01253                 if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01254                     router->nd_timer = 1;
01255                 } else {
01256                     router->nd_timer = nd_params.rs_retry_interval_min;
01257                 }
01258                 tr_debug("RS MC Done");
01259             } else {
01260                 router->nd_timer = 1;
01261                 tr_debug("RS Unicast Done");
01262                 mac_data_poll_protocol_poll_mode_decrement(cur);
01263             }
01264             router->ns_retry = nd_params.ns_retry_max;
01265             router->nd_state = ND_READY;
01266             router->nd_re_validate = (router_lifetime / 5) * 4;
01267         }
01268     }
01269 
01270     if (uptodate) {
01271         router->abro_version_num = abro_ver_num;
01272         router->life_time = router_lifetime;
01273     }
01274 
01275     return uptodate;
01276 }
01277 
01278 /* This processes the 6CO for the interface itself - separate from the ABRO
01279  * multihop relay storage.
01280  *
01281  *  0                   1                   2                   3
01282  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
01283  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01284  * |     Type      |     Length    |Context Length | Res |C|  CID  |
01285  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01286  * |            Reserved           |         Valid Lifetime        |
01287  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01288  * .                                                               .
01289  * .                       Context Prefix                          .
01290  * .                                                               .
01291  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01292  *
01293  */
01294 void nd_ra_process_lowpan_context_option(protocol_interface_info_entry_t *cur, const uint8_t *opt)
01295 {
01296     uint8_t opt_len = opt[1];
01297     uint8_t ctx_len = opt[2];
01298     uint8_t cid_flags = opt[3];
01299     uint16_t lifetime = common_read_16_bit(opt + 6);
01300 
01301     if (ctx_len > 128 || ctx_len > (opt_len - 1) * 64) {
01302         return;
01303     }
01304 
01305     lowpan_context_update(&cur->lowpan_contexts, cid_flags, lifetime, opt + 8, ctx_len, true);
01306 }
01307 #ifdef HAVE_6LOWPAN_ROUTER
01308 static void nd_ra_build(nd_router_t *cur, const uint8_t *address, protocol_interface_info_entry_t *cur_interface)
01309 {
01310     if (!(cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY) || !icmp_nd_router_prefix_valid(cur)) {
01311         return;
01312     }
01313 
01314     /* Base buffer size: RA Hdr = 12, ABRO = 24, MTU = up to 8, SLLAO = up to 16 */
01315     uint16_t length = 12 + 24 + 8 + 16;
01316     length += 32 * ns_list_count(&cur->prefix_list);
01317 
01318     ns_list_foreach(lowpan_context_t, context_ptr, &cur->context_list) {
01319         length += (context_ptr->length <= 64) ? 16 : 24;
01320     }
01321 
01322     buffer_t *db = buffer_get(length);
01323     if (!db) {
01324         return;
01325     } else if (addr_interface_get_ll_address(cur_interface, db->src_sa .address , 0) != 0) {
01326         buffer_free(db);
01327         return;
01328     }
01329     db->src_sa .addr_type  = ADDR_IPV6 ;
01330 
01331     uint8_t *dptr = buffer_data_pointer(db);
01332     *dptr++ = cur_interface->adv_cur_hop_limit;
01333     *dptr++ = cur->flags;
01334     dptr = common_write_16_bit(cur->life_time, dptr);
01335     dptr = common_write_32_bit(cur_interface->adv_reachable_time, dptr);
01336     dptr = common_write_32_bit(cur_interface->adv_retrans_timer, dptr);
01337 
01338     //SET ABRO
01339     *dptr++ = ICMPV6_OPT_AUTHORITATIVE_BORDER_RTR;
01340     *dptr++ = 3;        //Len * 8 byte
01341 
01342     dptr = common_write_16_bit((uint16_t)cur->abro_version_num, dptr);
01343     dptr = common_write_16_bit((uint16_t)(cur->abro_version_num >> 16), dptr);
01344     dptr = common_write_16_bit(0, dptr);
01345     memcpy(dptr, cur->border_router, 16);
01346     dptr += 16;
01347     //SET Prefixs
01348     dptr = icmpv6_write_prefix_option(&cur->prefix_list, dptr, 0, cur_interface);
01349 
01350     ns_list_foreach(lowpan_context_t, context_ptr, &cur->context_list) {
01351         *dptr++ = ICMPV6_OPT_6LOWPAN_CONTEXT;
01352         *dptr++ = (context_ptr->length <= 64) ? 2 : 3;
01353         *dptr++ = context_ptr->length;
01354         *dptr++ = context_ptr->cid | (context_ptr->compression ? LOWPAN_CONTEXT_C : 0);
01355         dptr = common_write_16_bit(0, dptr);
01356         dptr = common_write_16_bit((context_ptr->lifetime + 599) / 600, dptr);
01357         length = (context_ptr->length <= 64) ? 8 : 16;
01358         memcpy(dptr, context_ptr->prefix, length);
01359         dptr += length;
01360     }
01361 
01362     //MTU
01363     if (cur_interface->adv_link_mtu != 0) {
01364         dptr = icmpv6_write_mtu_option(cur_interface->adv_link_mtu, dptr);
01365     }
01366 
01367     /* RFC 6775 mandates SLLAO in RA */
01368     dptr = icmpv6_write_icmp_lla(cur_interface, dptr, ICMPV6_OPT_SRC_LL_ADDR, true, db->src_sa .address );
01369 
01370     if (address) {
01371         memcpy(db->dst_sa .address , address, 16);
01372     } else {
01373         memcpy(db->dst_sa .address , ADDR_LINK_LOCAL_ALL_NODES, 16);
01374     }
01375     buffer_data_end_set(db, dptr);
01376 
01377 
01378     db->dst_sa .addr_type  = ADDR_IPV6 ;
01379     db->interface  = cur_interface;
01380     db->info  = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);
01381     db->options .type  = ICMPV6_TYPE_INFO_RA;
01382     db->options .code  = 0;
01383     db->options .hop_limit  = 255;
01384     arm_net_protocol_packet_handler(db, cur_interface);
01385 
01386 }
01387 
01388 void nd_ra_build_by_abro(const uint8_t *abro, const uint8_t *dest, protocol_interface_info_entry_t *cur_interface)
01389 {
01390     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01391         if (addr_ipv6_equal(cur->border_router, abro)) {
01392             nd_ra_build(cur, dest, cur_interface);
01393         }
01394     }
01395 }
01396 
01397 
01398 void nd_trigger_ras_from_rs(const uint8_t *unicast_adr, protocol_interface_info_entry_t *cur_interface)
01399 {
01400     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01401         if (cur->nwk_id == cur_interface->nwk_id) {
01402             if (icmp_nd_router_prefix_valid(cur)) {
01403                 //Allocate
01404                 icmpv6_trigger_ra_from_rs(cur_interface, unicast_adr, cur->border_router);
01405             }
01406         } else {
01407             tr_error("BIND_CONFIRM FAIL!!");
01408         }
01409     }
01410 }
01411 
01412 void nd_ns_forward_timer_reset(uint8_t *root_adr)
01413 {
01414     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01415         if (memcmp(root_adr, cur->border_router, 16) == 0) {
01416             if (cur->ns_forward_timer) {
01417                 cur->ns_forward_timer = 0;
01418                 tr_warn("RX VALID DAC");
01419             }
01420             break;
01421         }
01422     }
01423 }
01424 
01425 static void nd_router_forward_timer(nd_router_t *cur, uint16_t ticks_update)
01426 {
01427     protocol_interface_info_entry_t *cur_interface;
01428     if (!(cur->ns_forward_timer)) {
01429         return;
01430     }
01431 
01432     if (cur->ns_forward_timer > ticks_update) {
01433         cur->ns_forward_timer -= ticks_update;
01434         return;
01435     }
01436 
01437     cur->ns_forward_timer = 0;
01438     cur_interface = protocol_stack_interface_info_get(cur->nwk_id);
01439     if (cur_interface) {
01440         if (cur->nd_re_validate > 10) {
01441             tr_debug("TRIG NS/ND");
01442             cur->nd_timer = 1;
01443             cur->nd_re_validate = 1;
01444         }
01445         if (cur_interface->if_6lowpan_dad_process.active == false) {
01446             nd_ns_trig(cur, cur_interface);
01447         }
01448     }
01449 }
01450 
01451 ipv6_ra_timing_t *nd_ra_timing(const uint8_t abro[16])
01452 {
01453     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01454         if (addr_ipv6_equal(abro, cur->border_router)) {
01455             return &cur->ra_timing;
01456         }
01457     }
01458 
01459     return NULL;
01460 }
01461 
01462 static nd_router_t *nd_router_object_scan_by_prefix(const uint8_t *ptr, nwk_interface_id nwk_id)
01463 {
01464     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01465         if (cur->nwk_id == nwk_id) {
01466             if (icmpv6_prefix_compare(&cur->prefix_list, ptr, 64)) {
01467                 return cur;
01468             }
01469         }
01470     }
01471 
01472     return NULL;
01473 }
01474 
01475 #endif
01476 
01477 void gp_address_add_to_end(gp_ipv6_address_list_t *list, const uint8_t address[static 16])
01478 {
01479     gp_ipv6_address_entry_t *new_entry;
01480 
01481     ns_list_foreach(gp_ipv6_address_entry_t, cur, list) {
01482         if (memcmp(cur->address, address, 16) == 0) {
01483             return;
01484         }
01485     }
01486 
01487     new_entry = ns_dyn_mem_alloc(sizeof(gp_ipv6_address_entry_t));
01488     if (!new_entry) {
01489         tr_warn("No heap for New Address");
01490         return;
01491     }
01492 
01493     memcpy(new_entry->address, address, 16);
01494     ns_list_add_to_end(list, new_entry);
01495 }
01496 
01497 /* Returns 1 if the router object has been removed */
01498 static uint8_t nd_router_ready_timer(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint16_t ticks_update)
01499 {
01500     if (!cur->nd_timer) {
01501         return 0;
01502     }
01503 
01504     if (cur->nd_timer > ticks_update) {
01505         cur->nd_timer -= ticks_update;
01506         return 0;
01507     }
01508 
01509     //Take out last remaing time from ticks
01510     ticks_update -= cur->nd_timer;
01511     uint16_t updated_seconds = 1;
01512     cur->nd_timer = 10;
01513     if (ticks_update) {
01514         updated_seconds += (ticks_update / 10);
01515         //Set Next second based on over based time
01516         cur->nd_timer -= (ticks_update % 10);
01517     }
01518 
01519     if (icmp_nd_router_prefix_ttl_update(cur, cur_interface, updated_seconds)) {
01520         return 1;
01521     }
01522 
01523     //Update seconds
01524     icmp_nd_router_context_ttl_update(cur, updated_seconds);
01525 
01526     if (!cur->nd_re_validate) {
01527         return 0;
01528     }
01529 
01530     if (cur->nd_re_validate > updated_seconds) {
01531         cur->nd_re_validate -= updated_seconds;
01532         //tr_debug("NDR:Tick Update %u", cur->nd_re_validate);
01533         return 0;
01534     }
01535 
01536     if (cur->nd_state == ND_READY) {
01537         tr_debug("RE ND Process: RS Unicast!");
01538         cur->ns_retry = nd_params.rs_retry_max;
01539         cur->nd_state = ND_RS_UNCAST;
01540         set_power_state(ICMP_ACTIVE);
01541         cur->nd_timer = 1;
01542         cur->nd_bootstrap_tick = (nd_base_tick - 1);
01543         if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
01544             mac_data_poll_init_protocol_poll(cur_interface);
01545         }
01546         nd_router_bootstrap_timer(cur, cur_interface, 1);
01547     } else { /* ND_BR_READY */
01548         nd_border_router_setup_refresh(cur->nwk_id, true);
01549         tr_debug("ND BR refresh ABRO");
01550         cur->nd_re_validate = (cur->life_time / 4) * 3;
01551         icmpv6_restart_router_advertisements(cur_interface, cur->border_router);
01552     }
01553     return 0;
01554 }
01555 
01556 /* Returns 1 if the router object has been removed, or we want no further processing on this tick */
01557 static uint8_t nd_router_bootstrap_timer(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint16_t ticks)
01558 {
01559     uint16_t scaled_ticks;
01560     /*
01561      * nd_timer is scaled by nd_base_tick during the discovery states,
01562      * to allow API to slow down the ND process. Note we count up and test
01563      * inequality, just in case someone decides to change nd_base_tick on
01564      * the fly.
01565      */
01566     if (cur->nd_bootstrap_tick + ticks < nd_base_tick) {
01567         cur->nd_bootstrap_tick += ticks;
01568         return 0;
01569     }
01570 
01571     //Take off scaled ticks
01572     ticks -= (nd_base_tick - cur->nd_bootstrap_tick);
01573 
01574     scaled_ticks = 1 + (ticks / nd_base_tick);
01575 
01576     cur->nd_bootstrap_tick = 0 + (ticks % nd_base_tick);
01577 
01578     if (!cur->nd_timer) {
01579         tr_debug("NDB:Tick Update fail %u", scaled_ticks);
01580         return 0;
01581     }
01582 
01583 
01584     if (cur->nd_timer > scaled_ticks) {
01585         cur->nd_timer -= scaled_ticks;
01586         return 0;
01587     }
01588 
01589     switch (cur->nd_state) {
01590 
01591         case ND_RS_UNCAST:
01592         case ND_RS_MULTICAST:
01593             if (cur->ns_retry) {
01594                 if (nd_rs_build(cur->nd_state == ND_RS_UNCAST ? cur : NULL, cur_interface)) {
01595                     cur->nd_timer = nd_params.rs_retry_interval_min;
01596                     cur->nd_timer += randLIB_get_16bit() & nd_params.timer_random_max;
01597                     cur->ns_retry--;
01598                     tr_debug(cur->nd_state == ND_RS_UNCAST ? "RS" : "RS+");
01599                 } else {
01600                     cur->nd_timer = 2;
01601                 }
01602             } else {
01603                 //ND FAIL
01604                 if (cur->nd_state == ND_RS_UNCAST) {
01605                     cur->ns_retry = nd_params.rs_retry_max;
01606                     cur->nd_state = ND_RS_MULTICAST;
01607                     cur->nd_timer = 1;
01608                 } else {
01609                     //RS UNICAST Fail
01610                     /*if (rpl_object_poisons() == 0) ??? */ {
01611                         protocol_6lowpan_bootstrap_re_start(cur_interface);
01612                     }
01613                     return 1;
01614                 }
01615             }
01616             break;
01617 
01618         case ND_READY:
01619         case ND_BR_READY:
01620             /* Not called for these states - put in to suppress GCC warning */
01621             break;
01622     }
01623 
01624     return 0;
01625 }
01626 
01627 
01628 void nd_object_timer(protocol_interface_info_entry_t *cur_interface, uint16_t ticks_update)
01629 {
01630     ns_list_foreach_safe(nd_router_t, cur, &nd_router_list) {
01631         /* This may nd_router_remove(cur), so need to use safe loop */
01632         if (cur_interface->nwk_id == cur->nwk_id) {
01633 
01634             protocol_6lowpan_link_advertise_handle(cur, cur_interface, ticks_update);
01635 
01636             if (cur->nd_state != ND_BR_READY) {
01637                 nd_router_forward_timer(cur, ticks_update);
01638             }
01639 
01640             if (nd_is_ready_state(cur->nd_state)) {
01641                 nd_router_ready_timer(cur, cur_interface, ticks_update);
01642             } else {
01643                 nd_router_bootstrap_timer(cur, cur_interface, ticks_update);
01644             }
01645             return;
01646         }
01647     }
01648 }
01649 
01650 uint32_t nd_object_time_to_next_nd_reg(void)
01651 {
01652     uint32_t ret_val = 0;
01653     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01654         if (cur->nd_state == ND_READY) {
01655             ret_val = cur->nd_re_validate;
01656             ret_val++;
01657             ret_val *= 1000;
01658             /* XXX surely this should find the shortest, not the first? */
01659             break;
01660         }
01661     }
01662     return ret_val;
01663 }
01664 
01665 uint8_t nd_prefix_dst_check(uint8_t *ptr)
01666 {
01667     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01668         if (icmpv6_prefix_compare(&cur->prefix_list, ptr, 64)) {
01669             return 1;
01670         }
01671     }
01672     return 0;
01673 }
01674 
01675 
01676 int8_t nd_parent_loose_indcate(uint8_t *neighbor_address, protocol_interface_info_entry_t *cur_interface)
01677 {
01678     int8_t ret_val = -1;
01679     addrtype_t adr_type = ADDR_802_15_4_LONG ;
01680     uint8_t *adr_ptr = neighbor_address;
01681     nd_router_next_hop *hop;
01682     uint8_t compare_len = 8;
01683 
01684     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01685         if (!(cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) {
01686             continue;
01687         }
01688 
01689         hop = &cur->default_hop;
01690         if (memcmp(neighbor_address, ADDR_SHORT_ADR_SUFFIC, 6) == 0) {
01691             adr_ptr += 6;
01692             adr_type = ADDR_802_15_4_SHORT ;
01693             compare_len = 2;
01694         }
01695         if (hop->addrtype == adr_type) {
01696             if (memcmp(hop->address, adr_ptr, compare_len) == 0) {
01697                 tr_debug("ND Primary Parent Lost");
01698 
01699                 if (cur->secondaty_hop == 0) {
01700                     ret_val = -1;
01701                 } else {
01702                     ret_val = 0;
01703                     tr_debug("Swap Secondary to primary");
01704                     memcpy(hop, cur->secondaty_hop, sizeof(nd_router_next_hop));
01705                     tr_debug("Trig NS/NA with new parent");
01706                     if (cur->nd_state == ND_READY) {
01707                         cur->nd_re_validate = 1;
01708                         if (cur_interface->if_6lowpan_dad_process.active == false) {
01709                             nd_ns_trig(cur, cur_interface);
01710                         }
01711                     }
01712                     ns_dyn_mem_free(cur->secondaty_hop);
01713                     cur->secondaty_hop = 0;
01714                 }
01715                 return ret_val;
01716             }
01717         } else if (cur->secondaty_hop) {
01718             hop = cur->secondaty_hop;
01719             if (hop->addrtype == adr_type) {
01720                 if (memcmp(hop->address, adr_ptr, compare_len) == 0) {
01721                     tr_debug("ND Secondary Parent Lost");
01722                     ns_dyn_mem_free(cur->secondaty_hop);
01723                     cur->secondaty_hop = 0;
01724                     return 0;
01725                 }
01726             }
01727         }
01728     }
01729     return -1;
01730 }
01731 
01732 nd_router_t *nd_get_object_by_nwk_id(nwk_interface_id nwk_id)
01733 {
01734     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01735         if (cur->nwk_id == nwk_id) {
01736             return cur;
01737         }
01738     }
01739 
01740     return 0;
01741 }
01742 
01743 nd_router_t *nd_get_pana_address(void)
01744 {
01745     return ns_list_get_first(&nd_router_list);
01746 }
01747 
01748 void nd_6lowpan_set_radv_params(protocol_interface_info_entry_t *cur_interface)
01749 {
01750 #ifndef NO_RADV_TX
01751     cur_interface->max_ra_delay_time = 20;
01752     cur_interface->min_delay_between_ras = 100;
01753     cur_interface->rtr_adv_unicast_to_rs = true;
01754     cur_interface->adv_cur_hop_limit = nd_params.ra_cur_hop_limit;
01755     cur_interface->adv_link_mtu = nd_params.ra_link_mtu;
01756     cur_interface->adv_reachable_time = nd_params.ra_reachable_time;
01757     cur_interface->adv_retrans_timer = nd_params.ra_retrans_timer;
01758     cur_interface->max_initial_rtr_adv_interval = nd_params.ra_interval_min;
01759     cur_interface->max_initial_rtr_advertisements = nd_params.ra_transmits;
01760 #endif
01761 }
01762 #endif // HAVE_6LOWPAN_ND
01763