Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_nd.c Source File

thread_nd.c

00001 /*
00002  * Copyright (c) 2014-2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: BSD-3-Clause
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holder nor the
00014  *    names of its contributors may be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * \file thread_nd.c
00032  * \brief Add short description about this file!!!
00033  *
00034  */
00035 
00036 #include "nsconfig.h"
00037 #ifdef HAVE_THREAD
00038 #ifdef HAVE_THREAD_NEIGHBOR_DISCOVERY
00039 #include <string.h>
00040 #include <ns_types.h>
00041 #include <nsdynmemLIB.h>
00042 #include "eventOS_event.h"
00043 #include "common_functions.h"
00044 #include "socket_api.h"
00045 #include "Core/include/ns_socket.h"
00046 #include "NWK_INTERFACE/Include/protocol.h"
00047 #include "Common_Protocols/ipv6.h"
00048 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
00049 #include "net_thread_test.h"
00050 #include "ns_trace.h"
00051 #include "6LoWPAN/Thread/thread_common.h"
00052 #include "6LoWPAN/Thread/thread_routing.h"
00053 #include "6LoWPAN/Thread/thread_neighbor_class.h"
00054 #include "6LoWPAN/Thread/thread_nd.h"
00055 #include "6LoWPAN/Thread/thread_joiner_application.h"
00056 #include "6LoWPAN/Thread/thread_resolution_client.h"
00057 #include "6LoWPAN/Thread/thread_resolution_server.h"
00058 #include "6LoWPAN/Thread/thread_bootstrap.h"
00059 #include "6LoWPAN/Thread/thread_bbr_api_internal.h"
00060 #include "6LoWPAN/Thread/thread_bbr_commercial.h"
00061 #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
00062 #include "6LoWPAN/MAC/mac_helper.h"
00063 #include "Common_Protocols/icmpv6.h"
00064 #include "MLE/mle.h"
00065 #include "dhcp_service_api.h"
00066 #include "Service_Libs/nd_proxy/nd_proxy.h"
00067 
00068 #define TRACE_GROUP "thdn"
00069 
00070 static thread_resolution_server_addr_query_cb  thread_nd_address_query_lookup;
00071 static thread_resolution_client_error_cb thread_nd_address_error;
00072 static thread_resolution_client_notification_cb thread_nd_coap_notification_callback;
00073 
00074 void thread_nd_service_delete(int8_t interfaceId)
00075 {
00076     (void)interfaceId;
00077 }
00078 
00079 int thread_nd_client_service_activate(int8_t interfaceId)
00080 {
00081     thread_resolution_client_init(interfaceId);
00082     thread_resolution_client_set_error_cb(interfaceId, thread_nd_address_error);
00083     return 0;
00084 }
00085 
00086 int thread_nd_service_activate(int8_t interfaceId)
00087 {
00088     /* We assume this is set before we activate, and doesn't change */
00089     thread_resolution_server_init(interfaceId, thread_nd_address_query_lookup);
00090     thread_resolution_client_init(interfaceId);
00091     thread_resolution_client_set_error_cb(interfaceId, thread_nd_address_error);
00092     thread_resolution_client_set_notification_cb(interfaceId, thread_nd_coap_notification_callback);
00093     return 0;
00094 }
00095 
00096 int thread_nd_service_disable(int8_t interfaceId)
00097 {
00098     /* Doesn't hurt if we call thread_resolution_xxx_delete unconditionally */
00099     thread_resolution_server_delete(interfaceId);
00100     thread_resolution_client_delete(interfaceId);
00101     return 0;
00102 }
00103 
00104 static bool thread_nd_probe_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry)
00105 {
00106     //Generate Ping
00107     tr_debug("Sending Ping Echo (NUD): %s", trace_ipv6(entry->ip_address));
00108 
00109     //ADD NeighCache
00110     icmpv6_build_echo_req(cur, entry->ip_address);
00111 
00112     return true;
00113 }
00114 
00115 static void thread_nd_coap_response_callback(int8_t interface_id, int8_t status, const uint8_t ip_addr[16], uint16_t loc_addr, uint32_t last_transaction_time, uint8_t *mleid)
00116 {
00117     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00118     if (!cur) {
00119         return;
00120     }
00121     (void) last_transaction_time;
00122     (void) mleid;
00123 
00124     ipv6_neighbour_t *neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, ip_addr);
00125     if (neighbour_entry) {
00126         if (status == 0) {
00127             uint8_t ll_addr[4];
00128             common_write_16_bit(cur->mac_parameters->pan_id, ll_addr + 0);
00129             common_write_16_bit(loc_addr, ll_addr + 2);
00130             ipv6_neighbour_update_from_na(&cur->ipv6_neighbour_cache, neighbour_entry, NA_S | NA_O | NA_R, ADDR_802_15_4_SHORT , ll_addr);
00131         } else {
00132             ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, neighbour_entry);
00133         }
00134     }
00135 }
00136 
00137 static void thread_nd_coap_notification_callback(int8_t interface_id, const uint8_t ip_addr[16], uint16_t loc_addr, const uint8_t ml_eid[8])
00138 {
00139     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00140     if (!cur) {
00141         return;
00142     }
00143 
00144     /* First check to see if we have an existing entry with different RLOC - we need to unicast error
00145      * notification to that old entry if so. */
00146     ipv6_neighbour_t *entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, ip_addr);
00147     if (entry && entry->ll_type == ADDR_802_15_4_SHORT ) {
00148         uint16_t old_entry_rloc = common_read_16_bit(entry->ll_address + 2);
00149         if (old_entry_rloc != loc_addr) {
00150             uint8_t old_entry_ip[16];
00151             thread_addr_write_mesh_local_16(old_entry_ip, common_read_16_bit(entry->ll_address + 2), cur->thread_info);
00152             tr_info("Proactive address change %s %04x->%04x", trace_ipv6(ip_addr), old_entry_rloc, loc_addr);
00153             thread_resolution_client_address_error(interface_id, old_entry_ip, ip_addr, ml_eid);
00154         }
00155     }
00156 
00157     /* Now treat as an unsolicited update (by address, because entry may be NULL) */
00158     uint8_t ll_addr[4];
00159     common_write_16_bit(cur->mac_parameters->pan_id, ll_addr + 0);
00160     common_write_16_bit(loc_addr, ll_addr + 2);
00161     ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, ip_addr, ADDR_802_15_4_SHORT , ll_addr);
00162 
00163     if (nd_proxy_enabled_for_upstream(cur->id)) {
00164         ipv6_route_add(ip_addr, 128, cur->id, NULL, ROUTE_THREAD_PROXIED_HOST, 3600, 0);
00165     }
00166 }
00167 
00168 static bool thread_nd_coap_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry, uint8_t seq)
00169 {
00170 
00171     if (thread_resolution_client_resolve(cur->id, entry->ip_address, thread_nd_coap_response_callback) < 0) {
00172         goto failed;
00173     }
00174     (void) seq;
00175 
00176     // "In progress" is indicated by returning true
00177     return true;
00178 
00179 failed:
00180     // Failure is indicated by removing the neighbour cache entry,
00181     // and returning true meaning "don't send normal ICMPv6 NS".
00182     ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, entry);
00183     return true;
00184 }
00185 
00186 
00187 bool thread_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry,  bool unicast, uint8_t seq)
00188 {
00189     // neighbor discovery active only for Routers and FEDs
00190     if (cur->thread_info->thread_device_mode != THREAD_DEVICE_MODE_FULL_END_DEVICE &&
00191             cur->thread_info->thread_device_mode != THREAD_DEVICE_MODE_ROUTER) {
00192         return true;
00193     }
00194     if (unicast) {
00195         return thread_nd_probe_transmit(cur, entry);
00196     } else {
00197         return thread_nd_coap_transmit(cur, entry, seq);
00198     }
00199 }
00200 
00201 static mac_neighbor_table_entry_t *thread_nd_child_mleid_get(protocol_interface_info_entry_t *cur, uint8_t *childAddress, uint8_t *mlmeid_ptr)
00202 {
00203     mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur), childAddress, ADDR_802_15_4_SHORT );
00204     if (entry && !entry->ffd_device ) {
00205         uint8_t *ptr = thread_neighbor_class_get_mleid(&cur->thread_info->neighbor_class, entry->index );
00206         if (ptr) {
00207             memcpy(mlmeid_ptr, ptr, 8);
00208             return entry;
00209         }
00210     }
00211     return NULL;
00212 }
00213 
00214 static int thread_nd_address_query_lookup(int8_t interface_id, const uint8_t target_addr[static 16], uint16_t *rloc, uint16_t *addr_out, bool *proxy, uint32_t *last_transaction_time, uint8_t *mleid_ptr)
00215 {
00216     (void) rloc;
00217     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00218     if (!cur) {
00219         return -1;
00220     }
00221 
00222     uint16_t mac16 = mac_helper_mac16_address_get(cur);
00223 
00224     if (addr_is_assigned_to_interface(cur, target_addr)) {
00225         *addr_out = mac16;
00226         memcpy(mleid_ptr, cur->iid_slaac, 8);
00227         *proxy = false;
00228         return 0;
00229     }
00230 
00231     /* Scan IPv6 neighbour cache for registered entries of children */
00232     ns_list_foreach(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) {
00233         if (n->type == IP_NEIGHBOUR_REGISTERED && addr_ipv6_equal(n->ip_address, target_addr)) {
00234             mac_neighbor_table_entry_t *mle_entry;
00235             *addr_out = mac16;
00236             mle_entry = thread_nd_child_mleid_get(cur, &n->ll_address[2], mleid_ptr);
00237             if (mle_entry) {
00238                 //Get MLEID from Child
00239                 uint32_t last_contact = thread_neighbor_last_communication_time_get(&cur->thread_info->neighbor_class, mle_entry->index );
00240                 *last_transaction_time = (protocol_core_monotonic_time - last_contact) / 10;  /* Both variables are count of 100ms ticks. */
00241                 *proxy = true;
00242                 return 0;
00243             }
00244         }
00245     }
00246 
00247     // IF we are acting as border router and we have enabled ND proxy. we respond to address
00248     // queries that are not registered to us if we can route those packets out.
00249     /* Verify DHCP Server Status */
00250     bool can_route_of_mesh = false;
00251 
00252     if (!nd_proxy_enabled_for_upstream(interface_id)) {
00253         //ND proxy not enabled can not answer
00254         return -1;
00255     }
00256 
00257     // TODO needed for eternal border router applications can be removed later
00258     if (libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface_id, target_addr)) {
00259         can_route_of_mesh = true;
00260     }
00261 
00262     // Check if we are registered as border router in network data.
00263     if (thread_bbr_routing_enabled(cur)) {
00264         can_route_of_mesh = true;
00265     }
00266 
00267     if (thread_bbr_commercial_nd_query_process(cur, target_addr, *rloc)) {
00268         return -1;
00269     }
00270 
00271     if (can_route_of_mesh) {
00272         ipv6_route_t *route = ipv6_route_choose_next_hop(target_addr, -1, NULL);
00273         //Respond default route only when we would route it of mesh.
00274         if (route && route->on_link && route->info.interface_id != interface_id) {
00275             *addr_out = mac16;
00276             memcpy(mleid_ptr, cur->iid_slaac, 8);
00277             *proxy = false;
00278             return 0;
00279         }
00280     }
00281 
00282     return -1;
00283 }
00284 
00285 static void thread_nd_address_error(int8_t interface_id, const uint8_t ip_addr[16], const uint8_t ml_eid[8])
00286 {
00287     protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
00288     if (!cur) {
00289         return;
00290     }
00291 
00292     /* Processing for ourselves - if we have the address, and the ML-EID in the
00293      * message is _not_ ours, we delete.
00294      */
00295     if_address_entry_t *addr_entry = addr_get_entry(cur, ip_addr);
00296     if (addr_entry && memcmp(ml_eid, cur->iid_slaac, 8)) {
00297         addr_duplicate_detected(cur, ip_addr);
00298         thread_bootstrap_dua_address_generate(cur, ip_addr, 64);
00299     }
00300 
00301     /* Scan IPv6 neighbour cache for registered entries of children */
00302     ns_list_foreach_safe(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) {
00303         if (n->type == IP_NEIGHBOUR_REGISTERED && addr_ipv6_equal(n->ip_address, ip_addr)) {
00304             uint8_t child_mleid[8];
00305             mac_neighbor_table_entry_t *child = thread_nd_child_mleid_get(cur, &n->ll_address[2], child_mleid);
00306             /* If this address belongs to an RFD child, with a different ML-EID, we must send it a duplicate message, and remove the EID */
00307             if (child && memcmp(child_mleid, ml_eid, 8)) {
00308                 uint8_t child_ml_addr[16];
00309                 thread_addr_write_mesh_local_16(child_ml_addr, child->mac16 , cur->thread_info);
00310                 tr_warn("Forwarding address error to child %04x", common_read_16_bit(&n->ll_address[2]));
00311                 thread_resolution_client_address_error(interface_id, child_ml_addr, ip_addr, ml_eid);
00312                 ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, n);
00313             }
00314         }
00315     }
00316 
00317     return;
00318 }
00319 
00320 /* Flush neighbour cache entries pointing at this 16-bit address, or (optionally) its children */
00321 void thread_nd_flush_neighbour_cache_for_short_addr(protocol_interface_info_entry_t *cur, uint16_t flushee, bool children)
00322 {
00323     ns_list_foreach_safe(ipv6_neighbour_t, entry, &cur->ipv6_neighbour_cache.list) {
00324         if (entry->ll_type != ADDR_802_15_4_SHORT  || entry->type != IP_NEIGHBOUR_GARBAGE_COLLECTIBLE) {
00325             continue;
00326         }
00327 
00328         uint16_t n16 = common_read_16_bit(entry->ll_address + 2);
00329         if (flushee == n16 || (children && flushee == thread_router_addr_from_addr(n16))) {
00330             ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, entry);
00331         }
00332     }
00333 }
00334 
00335 static buffer_t *thread_nd_icmp_error_to_mesh_originator(buffer_t *buf, protocol_interface_info_entry_t *cur, const sockaddr_t *ll_src)
00336 {
00337     /* First generate a normal ICMP error (to the IP source) */
00338     buf = icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_NO_ROUTE, 0);
00339     if (!buf) {
00340         return NULL;
00341     }
00342 
00343     /* Now the messed-up bit. The source gets nothing. This is going to the mesh originator */
00344     /* DST = ML16 derived from the mesh originator address */
00345     memcpy(buf->dst_sa .address , cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 8);
00346     memcpy(buf->dst_sa .address  + 8, ADDR_SHORT_ADR_SUFFIC, 6);
00347     buf->dst_sa .address [14] = ll_src->address [2];
00348     buf->dst_sa .address [15] = ll_src->address [3];
00349     /* Want 16-bit ML16 source - this should select it if available */
00350     const uint8_t *src = addr_select_source(cur, buf->dst_sa .address , SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT);
00351     if (!src) {
00352         return buffer_free(buf);
00353     }
00354     memcpy(buf->src_sa .address , src, 16);
00355 
00356     return buffer_free_route(buf);
00357 }
00358 
00359 /* Called when link layer passes up a unicast packet that was not for our
00360  * link-layer address. Our mesh handlers do this when they see a packet
00361  * addressed to a non-existent child or minimal function device child.
00362  */
00363 buffer_t *thread_nd_snoop(protocol_interface_info_entry_t *cur, buffer_t *buf, const sockaddr_t *ll_dst, const sockaddr_t *ll_src, bool *bounce)
00364 {
00365     /* If snooping, security check hasn't happened yet */
00366     if (buf->options .ll_security_bypass_rx ) {
00367         return buffer_free(buf);
00368     }
00369 
00370     /* We just drop it if it wasn't mesh-addressed (impossible)  */
00371     if (!(buf->options .lowpan_mesh_rx  && ll_src->addr_type  == ADDR_802_15_4_SHORT )) {
00372         return buffer_free(buf);
00373     }
00374 
00375     if (!mac_neighbor_table_address_discover(mac_neighbor_info(cur), &ll_dst->address [2], ADDR_802_15_4_SHORT )) {
00376         /* We now know this was a packet for a non-existent child */
00377         goto bounce;
00378     }
00379 
00380     /* Packet must have been mesh-addressed to a minimal-function child. This always */
00381     /* indicates a cache error, unless the IP destination was an ML16 (RLOC16). */
00382     if (!thread_addr_is_mesh_local_16(buf->dst_sa .address , cur) ||
00383             buf->dst_sa .address [14] != ll_dst->address [2] ||
00384             buf->dst_sa .address [15] != ll_dst->address [3]) {
00385         goto bounce;
00386     }
00387 
00388     /* Forward the packet according to IP destination - we've consistency checked
00389      * it is an ML16 matching the original mesh destination, so will get there fine. */
00390     buf->options .ll_not_ours_rx  = false;
00391     return buf;
00392 
00393 bounce:
00394     *bounce = true;
00395     return thread_nd_icmp_error_to_mesh_originator(buf, cur, ll_src);
00396 }
00397 
00398 /* Called when we've determined the packet isn't IP addressed to us, but has okay
00399  * security. Precedes any other checks like forwarding enabled, or destination
00400  * type, scope.
00401  */
00402 buffer_t *thread_nd_special_forwarding(protocol_interface_info_entry_t *cur, buffer_t *buf, const sockaddr_t *ll_src, bool *bounce)
00403 {
00404     /* Funny Thread rule
00405      *
00406      *    A cache error is detected if a device receives a packet containing
00407      *    a 6LoWPAN mesh header[1] and an EID destination IPv6 address where
00408      *    the mesh destination is the device's RLOC16 address [2] but the EID
00409      *    does not belong to the receiver or, if the receiver is a router,
00410      *    the EID has not been registered by any Child of the receiver.
00411      *
00412      *    When a cache error is detected, the receiving device must respond by
00413      *    sending an ICMPv6 Destination Unreachable message with the ICMPv6
00414      *    Code set to 0 (No route to destination) [3] to the packet's mesh source
00415      *
00416      * Return "No route" if on-link destination, received from mesh, and it's not
00417      * for us or a child. Note that we return this even if not a router;
00418      * normally hosts should silently drop wrongly-addressed packets.
00419      *
00420      * (If the addressed child doesn't exist at all, the packet gets sent to
00421      * thread_nd_snoop, generating an error there).
00422      *
00423      * XXX [1] Neighbouring routers optimise out the mesh header, breaking this
00424      * response.
00425      *
00426      * XXX [1b] Children also optimise out mesh headers, so a full-function child
00427      * that has a stale resolution of a minimal device to our router address needs
00428      * to get a failure response.
00429      *
00430      * XXX [2] Mesh destination may have been RLOC16 of a child, and we have snooped
00431      * because they're MTD.
00432      *
00433      * XXX [3] "No route (0)" is a silly choice of code; "address unreachable (3)"
00434      * would make more sense.
00435      */
00436 
00437     if (ll_src->addr_type  != ADDR_802_15_4_SHORT ) {
00438         return buf;
00439     }
00440 
00441     mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur), &ll_src->address [2], ADDR_802_15_4_SHORT );
00442 
00443     /* Due to note 1 and 1b above, full-function children / neighbor routers
00444      * who did resolve to an RLOC16 may have optimised out the mesh header.
00445      * So we check for either the mesh header being present, or it coming
00446      * from a full-function device (FFD) neighbor.
00447      *
00448      * (If it comes from a MTD child without a mesh header we always
00449      * forward as normal, attempting address resolution if necessary.
00450      * If it comes from a child with a mesh header and the IP destination
00451      * is not in our neighbour cache, we need to send the child an error
00452      * to clear its cache.)
00453      */
00454     if (!(buf->options .lowpan_mesh_rx  || (entry && entry->ffd_device ))) {
00455         return buf;
00456     }
00457 
00458     /* Link-local and ML16 addresses are not EIDs, so no error generation */
00459     if (addr_is_ipv6_link_local(buf->dst_sa .address ) || thread_addr_is_mesh_local_16(buf->dst_sa .address , cur)) {
00460         return buf;
00461     }
00462 
00463     buffer_routing_info_t *route = ipv6_buffer_route(buf);
00464     if (!route) {
00465         return buf;
00466     }
00467 
00468     if (route->route_info.interface_id != cur->id) {
00469         return buf;
00470     }
00471 
00472     /* On-link test - only perform this check for on-link prefixes - those will have next_hop == destination */
00473     /* Being on-link is what tells us an address is an "EID" rather than an arbitrary global IPv6 address */
00474     if (!addr_ipv6_equal(route->route_info.next_hop_addr, buf->dst_sa .address )) {
00475         return buf;
00476     }
00477 
00478     /* If it was addressed to us as an IP router, it's okay if the packet is for a child */
00479     if (thread_i_am_router(cur)) {
00480         //Check Registered Addresses
00481         ns_list_foreach(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) {
00482             if (n->type == IP_NEIGHBOUR_REGISTERED
00483                     && memcmp(n->ip_address, buf->dst_sa .address , 16) == 0) {
00484                 return buf;
00485             }
00486         }
00487     }
00488 
00489     *bounce = true;
00490     return thread_nd_icmp_error_to_mesh_originator(buf, cur, ll_src);
00491 }
00492 
00493 /* The handler for the packets transmitted above (draft-kelsey-thread-network-data-00) */
00494 buffer_t *thread_nd_icmp_handler(protocol_interface_info_entry_t *cur, buffer_t *buf, bool *bounce)
00495 {
00496     (void) bounce;
00497     /* Try to make sure we specifically "such an ICMP message", not normal ones */
00498     if (!thread_addr_is_mesh_local_16(buf->dst_sa .address , cur) || !thread_addr_is_mesh_local_16(buf->src_sa .address , cur)) {
00499         return buf;
00500     }
00501 
00502     if (buf->options .type  != ICMPV6_TYPE_ERROR_DESTINATION_UNREACH) {
00503         return buf;
00504     }
00505 
00506     if (buf->options .code  != ICMPV6_CODE_DST_UNREACH_NO_ROUTE) {
00507         return buf;
00508     }
00509 
00510     /* Make sure we have the original destination address from invoking packet */
00511     if (buffer_data_length(buf) < 4 + 40) {
00512         return buf;
00513     }
00514 
00515     const uint8_t *targetIP = buffer_data_pointer(buf) + 4 + 24;
00516 
00517     /* Try to look up the ML64 entry in the cache. */
00518     ipv6_neighbour_t *n = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, targetIP);
00519     if (!n || n->ll_type != ADDR_802_15_4_SHORT  || n->type != IP_NEIGHBOUR_GARBAGE_COLLECTIBLE) {
00520         return buf;
00521     }
00522 
00523     /* Invalidate that ML64 entry if its 16-bit address is equal to, or a child
00524      * of, the source of the ICMP message. If it doesn't match, suggests
00525      * a bogus packet - exit now.
00526      */
00527     uint16_t icmp16 = common_read_16_bit(buf->src_sa .address  + 14);
00528     uint16_t entry16 = common_read_16_bit(n->ll_address + 2);
00529     if (!thread_addr_is_equal_or_child(icmp16, entry16)) {
00530         return buf;
00531     }
00532 
00533     ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, n);
00534 
00535     return buf;
00536 }
00537 
00538 int thread_nd_address_registration(protocol_interface_info_entry_t *cur, const uint8_t *ipv6Address, uint16_t mac16, uint16_t panId, const uint8_t *mac64, bool *new_neighbour_created)
00539 {
00540     ipv6_neighbour_t *neigh;
00541     uint8_t ll_address[4];
00542     bool neighbor_created = false;
00543     common_write_16_bit(panId, ll_address + 0);
00544     common_write_16_bit(mac16, ll_address + 2);
00545     neigh = ipv6_neighbour_lookup_or_create(&cur->ipv6_neighbour_cache, ipv6Address);
00546     if (!neigh) {
00547         return -1;
00548     }
00549 
00550     uint8_t *nce_eui64 = ipv6_neighbour_eui64(&cur->ipv6_neighbour_cache, neigh);
00551     if (neigh->type == IP_NEIGHBOUR_REGISTERED && memcmp(nce_eui64, mac64, 8) != 0) {
00552         return -2;
00553     }
00554 
00555     /* New entry */
00556     if (neigh->state == IP_NEIGHBOUR_NEW) {
00557         neighbor_created = true;
00558     }
00559     memcpy(nce_eui64, mac64, 8);
00560     /* Set the LL address, ensure it's marked STALE */
00561     ipv6_neighbour_entry_update_unsolicited(&cur->ipv6_neighbour_cache, neigh, ADDR_802_15_4_SHORT , ll_address);
00562     neigh->type = IP_NEIGHBOUR_REGISTERED;
00563     neigh->lifetime = 0xffffffff; //Set Infinite
00564     ipv6_neighbour_set_state(&cur->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE);
00565     if (new_neighbour_created) {
00566         *new_neighbour_created = neighbor_created;
00567     }
00568     return 0;
00569 }
00570 
00571 void thread_nd_address_remove(protocol_interface_info_entry_t *cur_interface, addrtype_t ll_type, const uint8_t *ll_address)
00572 {
00573     ns_list_foreach_safe(ipv6_neighbour_t, cur, &cur_interface->ipv6_neighbour_cache.list) {
00574         if ((cur->type == IP_NEIGHBOUR_REGISTERED || cur->type == IP_NEIGHBOUR_TENTATIVE) && ipv6_neighbour_ll_addr_match(cur, ll_type, ll_address)) {
00575             ipv6_neighbour_entry_remove(&cur_interface->ipv6_neighbour_cache, cur);
00576         }
00577     }
00578 }
00579 
00580 bool thread_pbbr_aloc_map(protocol_interface_info_entry_t *cur, uint16_t *addr16)
00581 {
00582     if (*addr16 == 0xfc38) {
00583         uint8_t addr[16];
00584         if (0 == thread_common_primary_bbr_get(cur, addr, NULL, NULL, NULL)) {
00585             *addr16 = common_read_16_bit(addr + 14);
00586             return true;
00587         }
00588     }
00589     return false;
00590 }
00591 
00592 int thread_nd_map_anycast_address(protocol_interface_info_entry_t *cur, uint16_t *addr16)
00593 {
00594     // Nothing implemented for now
00595     uint16_t anycastAddress = *addr16;
00596     if (anycastAddress == 0xfc00) {
00597         // this is leader anycast address
00598         *addr16 = thread_router_addr_from_id(cur->thread_info->thread_leader_data->leaderRouterId);
00599         return 0;
00600     }
00601     if ((anycastAddress & 0xfff0) == 0xfc00) {
00602         // Check DHCPv6 anycast address mapping
00603         uint8_t context = anycastAddress;
00604         if (thread_nd_dhcp_anycast_address_mapping_from_network_data(&cur->thread_info->networkDataStorage, addr16, context)) {
00605             return 0;
00606         }
00607     }
00608 
00609     if ((anycastAddress & 0xfff0) == 0xfc10 || (anycastAddress & 0xfff0) == 0xfc20) {
00610         // service mapping to anycast address
00611         uint8_t S_id = anycastAddress & 0x0f;
00612         if (thread_nd_service_anycast_address_mapping_from_network_data(&cur->thread_info->networkDataStorage, addr16, S_id)) {
00613             return 0;
00614         }
00615     }
00616 
00617     if ((anycastAddress & 0xfff8) == 0xfc30) {
00618         // Commissioner anycast address mapping
00619         if (!cur->thread_info->registered_commissioner.commissioner_valid) {
00620             return -1;
00621         }
00622         if ((anycastAddress & 0x0007) != cur->thread_info->registered_commissioner.session_id % 8) {
00623             return -1;
00624         }
00625         *addr16 = common_read_16_bit(cur->thread_info->registered_commissioner.border_router_address + 14);
00626         return 0;
00627     }
00628     if (thread_pbbr_aloc_map(cur, addr16)) {
00629         return 0;
00630     }
00631 
00632     return -1;
00633 }
00634 
00635 #endif //HAVE_THREAD_NEIGHBOR_DISCOVERY
00636 #endif //HAVE_THREAD
00637