takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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-2018, 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     }
00724     else
00725 #endif
00726     {
00727         icmp_nd_set_nd_def_router_address(router, cur);
00728     }
00729 
00730     aro.status = ARO_SUCCESS;
00731     aro.present = true;
00732     aro.lifetime = (cur->life_time / 60) + 1;
00733     memcpy(aro.eui64, cur_interface->mac, 8);
00734 
00735     buf = icmpv6_build_ns(cur_interface, router, address_ptr, true, false, &aro);
00736     protocol_push(buf);
00737 }
00738 
00739 /* RFC 6775 Duplicate Address Request/Confirmation packets
00740  *
00741  *     0                   1                   2                   3
00742  *  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
00743  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00744  * |     Type      |     Code      |          Checksum             |
00745  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00746  * |    Status     |   Reserved    |     Registration Lifetime     |
00747  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00748  * |                                                               |
00749  * +                            EUI-64                             +
00750  * |                                                               |
00751  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00752  * |                                                               |
00753  * +                                                               +
00754  * |                                                               |
00755  * +                       Registered Address                      +
00756  * |                                                               |
00757  * +                                                               +
00758  * |                                                               |
00759  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00760  *
00761  * (and 8.2.1 implies this is can be followed by options, although
00762  * none are defined).
00763  */
00764 #ifdef HAVE_6LOWPAN_ROUTER
00765 static bool nd_dar_dac_valid(buffer_t *buf)
00766 {
00767     const uint8_t *dptr = buffer_data_pointer(buf);
00768 
00769     if (buf->options .code  != 0) {
00770         return false;
00771     }
00772 
00773     if (!icmpv6_options_well_formed_in_buffer(buf, 28)) {
00774         return false;
00775     }
00776 
00777     if (addr_is_ipv6_multicast(dptr + 12)) {
00778         return false;
00779     }
00780 
00781     if (addr_is_ipv6_unspecified(buf->src_sa .address ) ||
00782             addr_is_ipv6_multicast(buf->src_sa .address )) {
00783         return false;
00784     }
00785 
00786     return true;
00787 }
00788 #endif
00789 
00790 buffer_t *nd_dar_parse(buffer_t *buf, protocol_interface_info_entry_t *cur_interface)
00791 {
00792 #if defined WHITEBOARD && defined HAVE_6LOWPAN_BORDER_ROUTER
00793     uint8_t *dptr = buffer_data_pointer(buf);
00794     buffer_t *retbuf;
00795     uint8_t status;
00796     uint16_t lifetime;
00797     const uint8_t *eui64;
00798 
00799     if (!nd_dar_dac_valid(buf)) {
00800         goto drop;
00801     }
00802 
00803     status = *dptr;
00804     dptr += 2;
00805     lifetime = common_read_16_bit(dptr);
00806     dptr += 2;
00807 
00808     if (status != ARO_SUCCESS) {
00809         goto drop;
00810     }
00811 
00812     whiteboard_entry_t *wb;
00813 
00814     /* EUI-64 */
00815     eui64 = dptr;
00816     dptr += 8;
00817     tr_debug("DAR adr: %s, from %s", trace_ipv6(dptr), trace_ipv6(buf->src_sa .address ));
00818 
00819     //SET White board
00820     wb = whiteboard_table_update(dptr, eui64, &status);
00821     if (wb && status == ARO_SUCCESS) {
00822         memcpy(wb->address, dptr, 16);
00823         memcpy(wb->eui64, eui64, 8);
00824         wb->interface_index = cur_interface->id;
00825         wb->ttl = UINT24_C(60) * lifetime;
00826     }
00827 
00828     retbuf = icmpv6_build_dad(cur_interface, NULL, ICMPV6_TYPE_INFO_DAC, buf->src_sa .address , eui64, dptr, status, lifetime);
00829     if (retbuf) {
00830         buffer_free(buf);
00831         return retbuf;
00832     }
00833 
00834 drop:
00835 #endif
00836 
00837     return buffer_free(buf);
00838 }
00839 
00840 #ifdef HAVE_6LOWPAN_ROUTER
00841 static void nd_update_registration(protocol_interface_info_entry_t *cur_interface, ipv6_neighbour_t *neigh, const aro_t *aro)
00842 {
00843     /* We are about to send an ARO response - update our Neighbour Cache accordingly */
00844     if (aro->status == ARO_SUCCESS && aro->lifetime != 0) {
00845         neigh->type = IP_NEIGHBOUR_REGISTERED;
00846         neigh->lifetime = aro->lifetime * UINT32_C(60);
00847         ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00848         /* Register with 2 seconds off the lifetime - don't want the NCE to expire before the route */
00849         ipv6_route_add(neigh->ip_address, 128, cur_interface->id, NULL, ROUTE_ARO, neigh->lifetime - 2, 0);
00850 
00851         /* We need to know peer is a host before publishing - this needs MLE. Not yet established
00852          * what to do without MLE - might need special external/non-external prioritisation at root.
00853          * This "publish for RFD" rule comes from ZigBee IP.
00854          */
00855         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 );
00856 
00857         if (entry && !entry->ffd_device ) {
00858             rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime);
00859         }
00860         protocol_6lowpan_neighbor_address_state_synch(cur_interface, aro->eui64, neigh->ip_address + 8);
00861 
00862     } else {
00863         /* Um, no - can't transmit response if we remove NCE now! */
00864         //ipv6_neighbour_entry_remove(&cur_interface->ipv6_neighbour_cache, neigh);
00865         neigh->type = IP_NEIGHBOUR_TENTATIVE;
00866         neigh->lifetime = 2;
00867         ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00868         ipv6_route_add(neigh->ip_address, 128, cur_interface->id, NULL, ROUTE_ARO, 4, 0);
00869         rpl_control_unpublish_address(protocol_6lowpan_rpl_domain, neigh->ip_address);
00870     }
00871 }
00872 
00873 void nd_remove_registration(protocol_interface_info_entry_t *cur_interface, addrtype_t ll_type, const uint8_t *ll_address)
00874 {
00875 
00876     ns_list_foreach_safe(ipv6_neighbour_t, cur, &cur_interface->ipv6_neighbour_cache.list)
00877     {
00878         if ((cur->type == IP_NEIGHBOUR_REGISTERED
00879                 || cur->type == IP_NEIGHBOUR_TENTATIVE)
00880                 && ipv6_neighbour_ll_addr_match(cur, ll_type, ll_address)) {
00881             ipv6_route_delete(cur->ip_address, 128, cur_interface->id, NULL,
00882                               ROUTE_ARO);
00883             ipv6_neighbour_entry_remove(&cur_interface->ipv6_neighbour_cache,
00884                                         cur);
00885         }
00886     }
00887 }
00888 
00889 /* Process ICMP Neighbor Solicitation (RFC 4861 + RFC 6775) ARO. */
00890 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)
00891 {
00892     /* Ignore any ARO if source is link-local */
00893     if (addr_is_ipv6_link_local(src_addr)) {
00894         return true; /* Transmit NA, without ARO */
00895     }
00896 
00897     /* If we can't parse the SLLAO, then act as if no SLLAO: ignore ARO */
00898     sockaddr_t ll_addr;
00899     if (!cur_interface->if_llao_parse(cur_interface, slla_opt, &ll_addr)) {
00900         return true; /* Transmit NA, without ARO */
00901     }
00902 
00903     /*
00904      *  0                   1                   2                   3
00905      *  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
00906      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00907      * |   Type = 33   |   Length = 2  |    Status     |   Reserved    |
00908      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00909      * |           Reserved            |     Registration Lifetime     |
00910      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00911      * |                                                               |
00912      * +                            EUI-64                             +
00913      * |                                                               |
00914      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00915      */
00916     /* icmpv6_ns_handler has already checked incoming status == 0 */
00917     aro_out->lifetime = common_read_16_bit(aro_opt + 6);
00918     memcpy(aro_out->eui64, aro_opt + 8, 8);
00919 
00920     /* Check if we are already using this address ourself */
00921     if (addr_interface_address_compare(cur_interface, src_addr) == 0) {
00922         aro_out->present = true;
00923         aro_out->status = ARO_DUPLICATE;
00924         return true;
00925     }
00926 
00927     /* TODO - check hard upper limit on registrations? */
00928 
00929     /* We need to have entry in the Neighbour Cache */
00930     ipv6_neighbour_t *neigh = ipv6_neighbour_lookup_or_create(&cur_interface->ipv6_neighbour_cache, src_addr);
00931     if (!neigh) {
00932         aro_out->present = true;
00933         aro_out->status = ARO_FULL;
00934         return true;
00935     }
00936 
00937     uint8_t *nce_eui64 = ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh);
00938     if (neigh->state != IP_NEIGHBOUR_NEW) {
00939         switch (neigh->type) {
00940             case IP_NEIGHBOUR_TENTATIVE:
00941                 /* Is zero EUI-64 still possible? */
00942                 if (memcmp(nce_eui64, aro_out->eui64, 8) && memcmp(nce_eui64, ADDR_EUI64_ZERO, 8)) {
00943                     /* Have a Tentative NCE with different EUI-64 - ignore NS; two
00944                      * people trying to register at once. One should retry.
00945                      */
00946                     return false;
00947                 }
00948                 break;
00949             case IP_NEIGHBOUR_REGISTERED:
00950                 if (memcmp(nce_eui64, aro_out->eui64, 8)) {
00951                     /* Already registered with different EUI-64 - duplicate */
00952                     aro_out->present = true;
00953                     aro_out->status = ARO_DUPLICATE;
00954                     return true;
00955                 }
00956                 break;
00957             case IP_NEIGHBOUR_GARBAGE_COLLECTIBLE:
00958                 break;
00959         }
00960     }
00961 
00962     if (neigh->type != IP_NEIGHBOUR_REGISTERED) {
00963         neigh->type = IP_NEIGHBOUR_TENTATIVE;
00964         neigh->lifetime = TENTATIVE_NCE_LIFETIME;
00965         memcpy(nce_eui64, aro_out->eui64, 8);
00966     }
00967 
00968     /* Set the LL address, ensure it's marked STALE */
00969     ipv6_neighbour_entry_update_unsolicited(&cur_interface->ipv6_neighbour_cache, neigh, ll_addr.addr_type , ll_addr.address );
00970     ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00971     if (ws_info(cur_interface)) {
00972         aro_out->status = ARO_SUCCESS;
00973         aro_out->present = true;
00974         // Todo: this might not be needed...
00975         nd_update_registration(cur_interface, neigh, aro_out);
00976         return true;
00977     }
00978     if (cur_interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || nd_params.multihop_dad == false) {
00979         if (cur_interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
00980             whiteboard_entry_t *wb;
00981             wb = whiteboard_table_update(src_addr, aro_out->eui64, &aro_out->status);
00982             if (wb) {
00983                 if (aro_out->status == ARO_SUCCESS) {
00984                     memcpy(wb->address, src_addr, 16);
00985                     memcpy(wb->eui64, aro_out->eui64, 8);
00986                     wb->interface_index = cur_interface->id;
00987                     wb->ttl = 50000;//life_time;
00988                 }
00989             } else {
00990                 tr_warn("white Board Registry fail");
00991                 aro_out->status = ARO_FULL;
00992                 goto RESPONSE;
00993             }
00994         }
00995 
00996 RESPONSE:
00997         aro_out->present = true;
00998         nd_update_registration(cur_interface, neigh, aro_out);
00999         return true; /* Transmit NA */
01000     } else { /* Non-border router and multihop DAD: relay as DAR to Border Router */
01001         nd_router_t *nd_router_obj = 0;
01002 
01003         nd_router_obj = nd_router_object_scan_by_prefix(src_addr, cur_interface->nwk_id);
01004         if (!nd_router_obj) {
01005             /* Don't know where to send this. Do we say "yay" or "nay"? */
01006             /* For now, ignore ARO, as with old code; don't set aro_out.present */
01007             return true;
01008         }
01009 
01010         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);
01011         if (!buf) {
01012             return false;    /* Failed to build DAR - drop NS */
01013         }
01014 
01015         tr_debug("RX:NS --> TX DAR to Root");
01016         protocol_push(buf);
01017         if (nd_router_obj->ns_forward_timer == 0) {
01018             nd_router_obj->ns_forward_timer = nd_params.ns_forward_timeout;
01019         }
01020 
01021         return false; /* Tell ns_handler to not transmit now */
01022     }
01023 }
01024 
01025 buffer_t *nd_dac_handler(buffer_t *buf, protocol_interface_info_entry_t *cur)
01026 {
01027     uint8_t *dptr, target_address[16], *reg_address;
01028     aro_t aro;
01029 
01030     dptr = buffer_data_pointer(buf);
01031 
01032     if (!nd_dar_dac_valid(buf)) {
01033         return buffer_free(buf);
01034     }
01035 
01036     nd_ns_forward_timer_reset(buf->src_sa .address );
01037 
01038     aro.status  = *dptr;
01039     dptr += 2;
01040     aro.lifetime = common_read_16_bit(dptr);
01041     dptr += 2;
01042     /* EUI-64 */
01043     memcpy(aro.eui64, dptr, 8);
01044     dptr += 8;
01045     reg_address = dptr;
01046     dptr += 16;
01047 
01048     ipv6_neighbour_t *neigh = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, reg_address);
01049     if (!neigh || neigh->type == IP_NEIGHBOUR_GARBAGE_COLLECTIBLE || memcmp(ipv6_neighbour_eui64(&cur->ipv6_neighbour_cache, neigh), aro.eui64, 8)) {
01050         return buffer_free(buf);
01051     }
01052 
01053     nd_update_registration(cur, neigh, &aro);
01054 
01055     /* RFC 6775 has a bit of a hole here - what's the Target Address? */
01056     /* It's not in the DAC. We didn't record locally when we sent the DAR */
01057     /* I guess it's logical that we use a link-local address. We break */
01058     /* RFC 4861 by responding "solicited", but not to the NS Target... */
01059     /* However, my reading of RFC 4861 says that the receiver should do */
01060     /* the right thing. Only problem is that what if they really did want */
01061     /* to do a NUD probe for our GP addr, but included the ARO by mistake? */
01062     if (addr_interface_get_ll_address(cur, target_address, 0)) {
01063         return buffer_free(buf);
01064     }
01065 
01066     /* NA builder will send it to the address in the buffer's source */
01067     memcpy(buf->src_sa .address , reg_address, 16);
01068 
01069     buffer_t *na_buf = icmpv6_build_na(cur, true, true, false, target_address, &aro, buf->src_sa .address );
01070 
01071     buffer_free(buf);
01072 
01073     return na_buf;
01074 }
01075 #endif // HAVE_6LOWPAN_ROUTER
01076 
01077 /* Original ABRO-based all-in-one parser. This needs some rework to separate ABRO-related and unrelated bits */
01078 /* Returns "false" if ABRO suggested it was a stale message, so not worth handling in the normal code */
01079 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)
01080 {
01081     nd_router_t *router;
01082     uint32_t abro_ver_num;
01083     uint16_t temp16;
01084     bool uptodate = false;
01085 
01086     /* XXX this is really a 32-bit number these days */
01087     temp16 = common_read_16_bit(dptr);
01088     abro_ver_num = temp16;
01089     dptr += 2;
01090     temp16 = common_read_16_bit(dptr);
01091     //SET MSB bytes to 32-bit
01092     abro_ver_num |= ((uint32_t)temp16 << 16);
01093 
01094     dptr += 4;
01095     //If Border Router boot is state
01096 
01097     if(cur->border_router_setup)
01098     {
01099         if(memcmp(dptr, cur->border_router_setup->border_router_gp_adr, 16) == 0)
01100         {
01101             if (cur->border_router_setup->initActive) {
01102                 //save New Context
01103                 if (common_serial_number_greater_32(abro_ver_num, cur->border_router_setup->nd_border_router_configure->abro_version_num)) {
01104                     cur->border_router_setup->initActive = false;
01105                     cur->border_router_setup->nd_border_router_configure->abro_version_num = (abro_ver_num + 0x00010000);
01106                     cur->border_router_setup->nd_nwk->abro_version_num = (abro_ver_num + 0x00010000);
01107                 } else if(abro_ver_num == cur->border_router_setup->nd_border_router_configure->abro_version_num) {
01108 
01109                     cur->border_router_setup->initActive = false;
01110                     cur->border_router_setup->nd_border_router_configure->abro_version_num = (abro_ver_num + 0x00010000);
01111                     cur->border_router_setup->nd_nwk->abro_version_num = (abro_ver_num + 0x00010000);
01112                 }
01113             }
01114             return true;
01115         }
01116         return false;
01117     }
01118 
01119     router = icmp_nd_router_object_get(dptr, buf->interface ->nwk_id);
01120     if (!router) {
01121         return true;
01122     }
01123 
01124     if (router->default_hop.addrtype == ADDR_NONE ) {
01125         tr_debug("Create ND version");
01126 
01127         router->flags = ra_flags;
01128 
01129         uptodate = true;
01130         icmp_nd_set_next_hop(&router->default_hop, &buf->src_sa );
01131         router->default_hop.LQI = buf->options .lqi ;
01132 
01133         icmp_nd_prefixs_parse(buf, router, cur);
01134         icmp_nd_context_parse(buf, router);
01135 
01136         if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01137             //SET OnlY primary
01138             uint8_t address[8];
01139             if (router->default_hop.addrtype == ADDR_802_15_4_SHORT ) {
01140                 address[6] = router->default_hop.address[0];
01141                 address[7] = router->default_hop.address[1];
01142                 memcpy(address, ADDR_SHORT_ADR_SUFFIC, 6);
01143             } else {
01144                 memcpy(address, router->default_hop.address, 8);
01145             }
01146             protocol_6lowpan_neighbor_priority_update(cur, NULL, address);
01147         }
01148         router->nd_state = ND_READY;
01149         router->nd_re_validate = (router_lifetime / 5) * 4;
01150         router->nd_timer = 10;
01151     } else {
01152         bool new_router = icmp_nd_compare_to_def_next_hop(&router->default_hop, &buf->src_sa );
01153 
01154         if (abro_ver_num == router->abro_version_num) {
01155             /* Up-to-date for host processing, but don't necessarily process for multi-hop relaying */
01156             uptodate = true;
01157         }
01158 
01159         /* XXX this is really a 32-bit number these days */
01160         if (common_serial_number_greater_32(abro_ver_num, router->abro_version_num)) {
01161             uint32_t diff_update;
01162             diff_update = (abro_ver_num - router->abro_version_num);
01163             uptodate = true;
01164 
01165             //uprouter_info=1;
01166             if(diff_update >= 0x00010000)
01167             {
01168                 tr_debug("Border Router Boot Trig NS");
01169                 router->trig_address_reg = true;
01170             } else {
01171                 tr_debug("Next num");
01172             }
01173 
01174             icmpv6_prefix_list_free(&router->prefix_list);
01175 
01176             lowpan_context_list_free(&router->context_list);
01177 
01178             icmp_nd_prefixs_parse(buf, router, cur);
01179             router->trig_address_reg = false;
01180             icmp_nd_context_parse(buf, router);
01181             icmpv6_restart_router_advertisements(cur, router->border_router);
01182         } else if (router->default_hop.LQI < buf->options .lqi ) {
01183             /* XXX another zero-hysteresis parent swap */
01184             if (new_router) {
01185                 uint8_t *sec_ptr = NULL;
01186                 if (router->secondaty_hop == 0) {
01187                     router->secondaty_hop = ns_dyn_mem_alloc(sizeof(nd_router_next_hop));
01188                 } else {
01189                     nd_router_next_hop *hop = router->secondaty_hop;
01190                     sec_ptr = hop->address;
01191                     if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01192                         if (hop->addrtype == ADDR_802_15_4_SHORT ) {
01193                             hop->address[6] = hop->address[0];
01194                             hop->address[7] = hop->address[1];
01195                             memcpy(hop->address, ADDR_SHORT_ADR_SUFFIC, 6);
01196                         }
01197                     }
01198                 }
01199                 if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01200                     //Remove old secondary priority and set new primary
01201                     protocol_6lowpan_neighbor_priority_update(cur, sec_ptr, &buf->src_sa .address [8]);
01202                 }
01203                 //
01204                 if (router->secondaty_hop) {
01205                     memcpy(router->secondaty_hop, &router->default_hop, sizeof(nd_router_next_hop));
01206                 }
01207                 icmp_nd_set_next_hop(&router->default_hop, &buf->src_sa );
01208             }
01209             router->default_hop.LQI = buf->options .lqi ;
01210         } else if (new_router) {
01211             if (!router->secondaty_hop) {
01212                 router->secondaty_hop = ns_dyn_mem_alloc(sizeof(nd_router_next_hop));
01213                 if (router->secondaty_hop) {
01214                     router->secondaty_hop->LQI = 0;
01215                 }
01216             }
01217             if (router->secondaty_hop) {
01218                 if (router->secondaty_hop->LQI < buf->options .lqi ) {
01219                     icmp_nd_set_next_hop(router->secondaty_hop, &buf->src_sa );
01220                     router->secondaty_hop->LQI = buf->options .lqi ;
01221                     if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01222                         //SET only new primary
01223                         protocol_6lowpan_neighbor_priority_update(cur, 0, &buf->src_sa .address [8]);
01224                     }
01225                 }
01226             }
01227         }
01228         /* If waiting for an RS response */
01229         /* XXX this accepts it even if stale - no abro version check. Problem? */
01230         /* XXX this section below smells like stuff that should be outside this function */
01231         if (router->nd_state == ND_RS_UNCAST || router->nd_state == ND_RS_MULTICAST) {
01232             /* Set uptodate to true so we accept data into our interface tables.
01233              * Consistent with previous behaviour, but is this what we want?
01234              */
01235             uptodate = true;
01236             router->flags = ra_flags;
01237             icmp_nd_set_next_hop(&router->default_hop, &buf->src_sa );
01238             router->default_hop.LQI = buf->options .lqi ;
01239 
01240             icmp_nd_prefixs_parse(buf, router, cur);
01241             icmp_nd_context_parse(buf, router);
01242 
01243             if (router->nd_state == ND_RS_MULTICAST) {
01244                 if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
01245                     router->nd_timer = 1;
01246                 } else {
01247                     router->nd_timer = nd_params.rs_retry_interval_min;
01248                 }
01249                 tr_debug("RS MC Done");
01250             } else {
01251                 router->nd_timer = 1;
01252                 tr_debug("RS Unicast Done");
01253                 mac_data_poll_protocol_poll_mode_decrement(cur);
01254             }
01255             router->ns_retry = nd_params.ns_retry_max;
01256             router->nd_state = ND_READY;
01257             router->nd_re_validate = (router_lifetime / 5) * 4;
01258         }
01259     }
01260 
01261     if(uptodate)
01262     {
01263         router->abro_version_num = abro_ver_num;
01264         router->life_time = router_lifetime;
01265     }
01266 
01267     return uptodate;
01268 }
01269 
01270 /* This processes the 6CO for the interface itself - separate from the ABRO
01271  * multihop relay storage.
01272  *
01273  *  0                   1                   2                   3
01274  *  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
01275  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01276  * |     Type      |     Length    |Context Length | Res |C|  CID  |
01277  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01278  * |            Reserved           |         Valid Lifetime        |
01279  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01280  * .                                                               .
01281  * .                       Context Prefix                          .
01282  * .                                                               .
01283  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01284  *
01285  */
01286 void nd_ra_process_lowpan_context_option(protocol_interface_info_entry_t *cur, const uint8_t *opt)
01287 {
01288     uint8_t opt_len = opt[1];
01289     uint8_t ctx_len = opt[2];
01290     uint8_t cid_flags = opt[3];
01291     uint16_t lifetime = common_read_16_bit(opt + 6);
01292 
01293     if (ctx_len > 128 || ctx_len > (opt_len - 1) * 64) {
01294         return;
01295     }
01296 
01297     lowpan_context_update(&cur->lowpan_contexts, cid_flags, lifetime, opt + 8, ctx_len, true);
01298 }
01299 #ifdef HAVE_6LOWPAN_ROUTER
01300 static void nd_ra_build(nd_router_t *cur, const uint8_t *address, protocol_interface_info_entry_t *cur_interface)
01301 {
01302     if (!(cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY) || !icmp_nd_router_prefix_valid(cur)) {
01303         return;
01304     }
01305 
01306     /* Base buffer size: RA Hdr = 12, ABRO = 24, MTU = up to 8, SLLAO = up to 16 */
01307     uint16_t length = 12 + 24 + 8 + 16;
01308     length += 32 * ns_list_count(&cur->prefix_list);
01309 
01310     ns_list_foreach(lowpan_context_t, context_ptr, &cur->context_list) {
01311         length += (context_ptr->length <= 64) ? 16 : 24;
01312     }
01313 
01314     buffer_t *db = buffer_get(length);
01315     if (!db) {
01316         return;
01317     } else if (addr_interface_get_ll_address(cur_interface, db->src_sa .address , 0) != 0) {
01318         buffer_free(db);
01319         return;
01320     }
01321     db->src_sa .addr_type  = ADDR_IPV6 ;
01322 
01323     uint8_t *dptr = buffer_data_pointer(db);
01324     *dptr++ = cur_interface->adv_cur_hop_limit;
01325     *dptr++ = cur->flags;
01326     dptr = common_write_16_bit(cur->life_time, dptr);
01327     dptr = common_write_32_bit(cur_interface->adv_reachable_time, dptr);
01328     dptr = common_write_32_bit(cur_interface->adv_retrans_timer, dptr);
01329 
01330     //SET ABRO
01331     *dptr++ = ICMPV6_OPT_AUTHORITATIVE_BORDER_RTR;
01332     *dptr++ = 3;        //Len * 8 byte
01333 
01334     dptr = common_write_16_bit((uint16_t)cur->abro_version_num, dptr);
01335     dptr = common_write_16_bit((uint16_t)(cur->abro_version_num >> 16), dptr);
01336     dptr = common_write_16_bit(0, dptr);
01337     memcpy(dptr, cur->border_router, 16);
01338     dptr += 16;
01339     //SET Prefixs
01340     dptr = icmpv6_write_prefix_option(&cur->prefix_list, dptr, 0, cur_interface);
01341 
01342     ns_list_foreach(lowpan_context_t, context_ptr, &cur->context_list) {
01343         *dptr++ = ICMPV6_OPT_6LOWPAN_CONTEXT;
01344         *dptr++ = (context_ptr->length <= 64) ? 2 : 3;
01345         *dptr++ = context_ptr->length;
01346         *dptr++ = context_ptr->cid | (context_ptr->compression ? LOWPAN_CONTEXT_C : 0);
01347         dptr = common_write_16_bit(0, dptr);
01348         dptr = common_write_16_bit((context_ptr->lifetime + 599) / 600, dptr);
01349         length = (context_ptr->length <= 64) ? 8 : 16;
01350         memcpy(dptr, context_ptr->prefix, length);
01351         dptr += length;
01352     }
01353 
01354     //MTU
01355     if (cur_interface->adv_link_mtu != 0) {
01356         dptr = icmpv6_write_mtu_option(cur_interface->adv_link_mtu, dptr);
01357     }
01358 
01359     /* RFC 6775 mandates SLLAO in RA */
01360     dptr = icmpv6_write_icmp_lla(cur_interface, dptr, ICMPV6_OPT_SRC_LL_ADDR, true, db->src_sa .address );
01361 
01362     if (address) {
01363         memcpy(db->dst_sa .address , address, 16);
01364     } else {
01365         memcpy(db->dst_sa .address , ADDR_LINK_LOCAL_ALL_NODES, 16);
01366     }
01367     buffer_data_end_set(db, dptr);
01368 
01369 
01370     db->dst_sa .addr_type  = ADDR_IPV6 ;
01371     db->interface  = cur_interface;
01372     db->info  = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);
01373     db->options .type  = ICMPV6_TYPE_INFO_RA;
01374     db->options .code  = 0;
01375     db->options .hop_limit  = 255;
01376     arm_net_protocol_packet_handler(db, cur_interface);
01377 
01378 }
01379 
01380 void nd_ra_build_by_abro(const uint8_t *abro, const uint8_t *dest, protocol_interface_info_entry_t *cur_interface)
01381 {
01382     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01383         if (addr_ipv6_equal(cur->border_router, abro)) {
01384             nd_ra_build(cur, dest, cur_interface);
01385         }
01386     }
01387 }
01388 
01389 
01390 void nd_trigger_ras_from_rs(const uint8_t *unicast_adr, protocol_interface_info_entry_t *cur_interface)
01391 {
01392     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01393         if (cur->nwk_id == cur_interface->nwk_id) {
01394             if (icmp_nd_router_prefix_valid(cur)) {
01395                 //Allocate
01396                 icmpv6_trigger_ra_from_rs(cur_interface, unicast_adr, cur->border_router);
01397             }
01398         } else {
01399             tr_error("BIND_CONFIRM FAIL!!");
01400         }
01401     }
01402 }
01403 
01404 void nd_ns_forward_timer_reset(uint8_t *root_adr)
01405 {
01406     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01407         if (memcmp(root_adr, cur->border_router, 16) == 0) {
01408             if (cur->ns_forward_timer) {
01409                 cur->ns_forward_timer = 0;
01410                 tr_warn("RX VALID DAC");
01411             }
01412             break;
01413         }
01414     }
01415 }
01416 
01417 static void nd_router_forward_timer(nd_router_t *cur, uint16_t ticks_update)
01418 {
01419     protocol_interface_info_entry_t *cur_interface;
01420     if (!(cur->ns_forward_timer)) {
01421         return;
01422     }
01423 
01424     if (cur->ns_forward_timer > ticks_update) {
01425         cur->ns_forward_timer -= ticks_update;
01426         return;
01427     }
01428 
01429     cur->ns_forward_timer = 0;
01430     cur_interface = protocol_stack_interface_info_get(cur->nwk_id);
01431     if (cur_interface) {
01432         if (cur->nd_re_validate > 10) {
01433             tr_debug("TRIG NS/ND");
01434             cur->nd_timer = 1;
01435             cur->nd_re_validate = 1;
01436         }
01437         if (cur_interface->if_6lowpan_dad_process.active == false) {
01438             nd_ns_trig(cur, cur_interface);
01439         }
01440     }
01441 }
01442 
01443 ipv6_ra_timing_t *nd_ra_timing(const uint8_t abro[16])
01444 {
01445     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01446         if (addr_ipv6_equal(abro, cur->border_router)) {
01447             return &cur->ra_timing;
01448         }
01449     }
01450 
01451     return NULL;
01452 }
01453 
01454 static nd_router_t *nd_router_object_scan_by_prefix(const uint8_t *ptr, nwk_interface_id nwk_id)
01455 {
01456     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01457         if (cur->nwk_id == nwk_id) {
01458             if (icmpv6_prefix_compare(&cur->prefix_list, ptr, 64)) {
01459                 return cur;
01460             }
01461         }
01462     }
01463 
01464     return NULL;
01465 }
01466 
01467 #endif
01468 
01469 void gp_address_add_to_end(gp_ipv6_address_list_t *list, const uint8_t address[static 16])
01470 {
01471     gp_ipv6_address_entry_t *new_entry;
01472 
01473     ns_list_foreach(gp_ipv6_address_entry_t, cur, list) {
01474         if (memcmp(cur->address, address, 16) == 0) {
01475             return;
01476         }
01477     }
01478 
01479     new_entry = ns_dyn_mem_alloc(sizeof(gp_ipv6_address_entry_t));
01480     if (!new_entry) {
01481         tr_warn("No heap for New Address");
01482         return;
01483     }
01484 
01485     memcpy(new_entry->address, address, 16);
01486     ns_list_add_to_end(list, new_entry);
01487 }
01488 
01489 /* Returns 1 if the router object has been removed */
01490 static uint8_t nd_router_ready_timer(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint16_t ticks_update)
01491 {
01492     if (!cur->nd_timer) {
01493         return 0;
01494     }
01495 
01496     if (cur->nd_timer > ticks_update ) {
01497         cur->nd_timer -= ticks_update;
01498         return 0;
01499     }
01500 
01501     //Take out last remaing time from ticks
01502     ticks_update -= cur->nd_timer;
01503     uint16_t updated_seconds = 1;
01504     cur->nd_timer = 10;
01505     if (ticks_update) {
01506         updated_seconds += (ticks_update / 10);
01507         //Set Next second based on over based time
01508         cur->nd_timer -= (ticks_update % 10);
01509     }
01510 
01511     if (icmp_nd_router_prefix_ttl_update(cur, cur_interface, updated_seconds)) {
01512         return 1;
01513     }
01514 
01515     //Update seconds
01516     icmp_nd_router_context_ttl_update(cur, updated_seconds);
01517 
01518     if (!cur->nd_re_validate) {
01519         return 0;
01520     }
01521 
01522     if (cur->nd_re_validate > updated_seconds) {
01523         cur->nd_re_validate -= updated_seconds;
01524         //tr_debug("NDR:Tick Update %u", cur->nd_re_validate);
01525         return 0;
01526     }
01527 
01528     if (cur->nd_state == ND_READY) {
01529         tr_debug("RE ND Process: RS Unicast!");
01530         cur->ns_retry = nd_params.rs_retry_max;
01531         cur->nd_state = ND_RS_UNCAST;
01532         set_power_state(ICMP_ACTIVE);
01533         cur->nd_timer = 1;
01534         cur->nd_bootstrap_tick = (nd_base_tick -1);
01535         if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
01536             mac_data_poll_init_protocol_poll(cur_interface);
01537         }
01538         nd_router_bootstrap_timer(cur,cur_interface,1);
01539     }
01540     else { /* ND_BR_READY */
01541         nd_border_router_setup_refresh(cur->nwk_id, true);
01542         tr_debug("ND BR refresh ABRO");
01543         cur->nd_re_validate = (cur->life_time / 4) * 3;
01544         icmpv6_restart_router_advertisements(cur_interface, cur->border_router);
01545     }
01546     return 0;
01547 }
01548 
01549 /* Returns 1 if the router object has been removed, or we want no further processing on this tick */
01550 static uint8_t nd_router_bootstrap_timer(nd_router_t *cur, protocol_interface_info_entry_t *cur_interface, uint16_t ticks)
01551 {
01552     uint16_t scaled_ticks;
01553     /*
01554      * nd_timer is scaled by nd_base_tick during the discovery states,
01555      * to allow API to slow down the ND process. Note we count up and test
01556      * inequality, just in case someone decides to change nd_base_tick on
01557      * the fly.
01558      */
01559     if (cur->nd_bootstrap_tick + ticks < nd_base_tick) {
01560         cur->nd_bootstrap_tick += ticks;
01561         return 0;
01562     }
01563 
01564     //Take off scaled ticks
01565     ticks -= (nd_base_tick - cur->nd_bootstrap_tick);
01566 
01567     scaled_ticks = 1 + (ticks / nd_base_tick);
01568 
01569     cur->nd_bootstrap_tick = 0 + (ticks % nd_base_tick);
01570 
01571     if (!cur->nd_timer) {
01572         tr_debug("NDB:Tick Update fail %u", scaled_ticks);
01573         return 0;
01574     }
01575 
01576 
01577     if (cur->nd_timer > scaled_ticks) {
01578         cur->nd_timer -= scaled_ticks;
01579         return 0;
01580     }
01581 
01582     switch (cur->nd_state) {
01583 
01584         case ND_RS_UNCAST:
01585         case ND_RS_MULTICAST:
01586             if (cur->ns_retry) {
01587                 if (nd_rs_build(cur->nd_state == ND_RS_UNCAST ? cur : NULL, cur_interface)) {
01588                     cur->nd_timer = nd_params.rs_retry_interval_min;
01589                     cur->nd_timer += randLIB_get_16bit() & nd_params.timer_random_max;
01590                     cur->ns_retry--;
01591                     tr_debug(cur->nd_state == ND_RS_UNCAST ? "RS" : "RS+");
01592                 } else {
01593                     cur->nd_timer = 2;
01594                 }
01595             } else {
01596                 //ND FAIL
01597                 if (cur->nd_state == ND_RS_UNCAST) {
01598                     cur->ns_retry = nd_params.rs_retry_max;
01599                     cur->nd_state = ND_RS_MULTICAST;
01600                     cur->nd_timer = 1;
01601                 } else {
01602                     //RS UNICAST Fail
01603                     /*if (rpl_object_poisons() == 0) ??? */ {
01604                         protocol_6lowpan_bootstrap_re_start(cur_interface);
01605                     }
01606                     return 1;
01607                 }
01608             }
01609             break;
01610 
01611         case ND_READY:
01612         case ND_BR_READY:
01613             /* Not called for these states - put in to suppress GCC warning */
01614             break;
01615     }
01616 
01617     return 0;
01618 }
01619 
01620 
01621 void nd_object_timer(protocol_interface_info_entry_t *cur_interface, uint16_t ticks_update)
01622 {
01623     ns_list_foreach_safe(nd_router_t, cur, &nd_router_list) {
01624         /* This may nd_router_remove(cur), so need to use safe loop */
01625         if (cur_interface->nwk_id == cur->nwk_id) {
01626 
01627             protocol_6lowpan_link_advertise_handle(cur, cur_interface, ticks_update);
01628 
01629             if (cur->nd_state != ND_BR_READY) {
01630                 nd_router_forward_timer(cur, ticks_update);
01631             }
01632 
01633             if (nd_is_ready_state(cur->nd_state)) {
01634                 nd_router_ready_timer(cur, cur_interface, ticks_update);
01635             } else {
01636                 nd_router_bootstrap_timer(cur, cur_interface, ticks_update);
01637             }
01638             return;
01639         }
01640     }
01641 }
01642 
01643 uint32_t nd_object_time_to_next_nd_reg(void)
01644 {
01645     uint32_t ret_val = 0;
01646     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01647         if (cur->nd_state == ND_READY) {
01648             ret_val = cur->nd_re_validate;
01649             ret_val++;
01650             ret_val *= 1000;
01651             /* XXX surely this should find the shortest, not the first? */
01652             break;
01653         }
01654     }
01655     return ret_val;
01656 }
01657 
01658 uint8_t nd_prefix_dst_check(uint8_t *ptr)
01659 {
01660     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01661         if (icmpv6_prefix_compare(&cur->prefix_list, ptr, 64)) {
01662             return 1;
01663         }
01664     }
01665     return 0;
01666 }
01667 
01668 
01669 int8_t nd_parent_loose_indcate(uint8_t *neighbor_address, protocol_interface_info_entry_t *cur_interface)
01670 {
01671     int8_t ret_val = -1;
01672     addrtype_t adr_type = ADDR_802_15_4_LONG ;
01673     uint8_t *adr_ptr = neighbor_address;
01674     nd_router_next_hop *hop;
01675     uint8_t compare_len = 8;
01676 
01677     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01678         if (!(cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) {
01679             continue;
01680         }
01681 
01682         hop = &cur->default_hop;
01683         if (memcmp(neighbor_address, ADDR_SHORT_ADR_SUFFIC, 6) == 0) {
01684             adr_ptr += 6;
01685             adr_type = ADDR_802_15_4_SHORT ;
01686             compare_len = 2;
01687         }
01688         if (hop->addrtype == adr_type) {
01689             if (memcmp(hop->address, adr_ptr, compare_len) == 0) {
01690                 tr_debug("ND Primary Parent Lost");
01691 
01692                 if (cur->secondaty_hop == 0) {
01693                     ret_val = -1;
01694                 } else {
01695                     ret_val = 0;
01696                     tr_debug("Swap Secondary to primary");
01697                     memcpy(hop, cur->secondaty_hop, sizeof(nd_router_next_hop));
01698                     tr_debug("Trig NS/NA with new parent");
01699                     if (cur->nd_state == ND_READY) {
01700                         cur->nd_re_validate = 1;
01701                         if (cur_interface->if_6lowpan_dad_process.active == false) {
01702                             nd_ns_trig(cur, cur_interface);
01703                         }
01704                     }
01705                     ns_dyn_mem_free(cur->secondaty_hop);
01706                     cur->secondaty_hop = 0;
01707                 }
01708                 return ret_val;
01709             }
01710         } else if (cur->secondaty_hop) {
01711             hop = cur->secondaty_hop;
01712             if (hop->addrtype == adr_type) {
01713                 if (memcmp(hop->address, adr_ptr, compare_len) == 0) {
01714                     tr_debug("ND Secondary Parent Lost");
01715                     ns_dyn_mem_free(cur->secondaty_hop);
01716                     cur->secondaty_hop = 0;
01717                     return 0;
01718                 }
01719             }
01720         }
01721     }
01722     return -1;
01723 }
01724 
01725 nd_router_t *nd_get_object_by_nwk_id(nwk_interface_id nwk_id)
01726 {
01727     ns_list_foreach(nd_router_t, cur, &nd_router_list) {
01728         if (cur->nwk_id == nwk_id) {
01729             return cur;
01730         }
01731     }
01732 
01733     return 0;
01734 }
01735 
01736 nd_router_t *nd_get_pana_address(void)
01737 {
01738     return ns_list_get_first(&nd_router_list);
01739 }
01740 
01741 void nd_6lowpan_set_radv_params(protocol_interface_info_entry_t *cur_interface)
01742 {
01743 #ifndef NO_RADV_TX
01744     cur_interface->max_ra_delay_time = 20;
01745     cur_interface->min_delay_between_ras = 100;
01746     cur_interface->rtr_adv_unicast_to_rs = true;
01747     cur_interface->adv_cur_hop_limit = nd_params.ra_cur_hop_limit;
01748     cur_interface->adv_link_mtu = nd_params.ra_link_mtu;
01749     cur_interface->adv_reachable_time = nd_params.ra_reachable_time;
01750     cur_interface->adv_retrans_timer = nd_params.ra_retrans_timer;
01751     cur_interface->max_initial_rtr_adv_interval = nd_params.ra_interval_min;
01752     cur_interface->max_initial_rtr_advertisements = nd_params.ra_transmits;
01753 #endif
01754 }
01755 #endif // HAVE_6LOWPAN_ND
01756