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