Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
thread_nd.c
00001 /* 00002 * Copyright (c) 2014-2018, 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/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_extension.h" 00057 #include "6LoWPAN/Thread/thread_resolution_client.h" 00058 #include "6LoWPAN/Thread/thread_resolution_server.h" 00059 #include "6LoWPAN/Thread/thread_bbr_api_internal.h" 00060 #include "6LoWPAN/Thread/thread_extension_bbr.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_warn("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 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00217 if (!cur) { 00218 return -1; 00219 } 00220 00221 uint16_t mac16 = mac_helper_mac16_address_get(cur); 00222 00223 if (addr_is_assigned_to_interface(cur, target_addr)) { 00224 *addr_out = mac16; 00225 memcpy(mleid_ptr, cur->iid_slaac, 8); 00226 *proxy = false; 00227 return 0; 00228 } 00229 00230 /* Scan IPv6 neighbour cache for registered entries of children */ 00231 ns_list_foreach(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) { 00232 if (n->type == IP_NEIGHBOUR_REGISTERED && addr_ipv6_equal(n->ip_address, target_addr)) { 00233 mac_neighbor_table_entry_t *mle_entry; 00234 *addr_out = mac16; 00235 mle_entry = thread_nd_child_mleid_get(cur, &n->ll_address[2], mleid_ptr); 00236 if (mle_entry) { 00237 //Get MLEID from Child 00238 uint32_t last_contact = thread_neighbor_last_communication_time_get(&cur->thread_info->neighbor_class, mle_entry->index ); 00239 *last_transaction_time = (protocol_core_monotonic_time - last_contact) / 10; /* Both variables are count of 100ms ticks. */ 00240 *proxy = true; 00241 return 0; 00242 } 00243 } 00244 } 00245 00246 // IF we are acting as border router and we have enabled ND proxy. we respond to address 00247 // queries that are not registered to us if we can route those packets out. 00248 /* Verify DHCP Server Status */ 00249 bool can_route_of_mesh = false; 00250 00251 if (!nd_proxy_enabled_for_upstream(interface_id) ) { 00252 //ND proxy not enabled can not answer 00253 return -1; 00254 } 00255 00256 // TODO needed for eternal border router applications can be removed later 00257 if ( libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface_id, target_addr) ){ 00258 can_route_of_mesh = true; 00259 } 00260 00261 // Check if we are registered as border router in network data. 00262 if(thread_bbr_routing_enabled(cur)) { 00263 can_route_of_mesh = true; 00264 } 00265 00266 if (thread_extension_bbr_nd_query_process(cur,target_addr, *rloc)){ 00267 return -1; 00268 } 00269 00270 if (can_route_of_mesh) { 00271 ipv6_route_t *route = ipv6_route_choose_next_hop(target_addr, -1, NULL); 00272 //Respond default route only when we would route it of mesh. 00273 if (route && route->on_link && route->info.interface_id != interface_id) { 00274 *addr_out = mac16; 00275 memcpy(mleid_ptr, cur->iid_slaac, 8); 00276 *proxy = false; 00277 return 0; 00278 } 00279 } 00280 00281 return -1; 00282 } 00283 00284 static void thread_nd_address_error(int8_t interface_id, const uint8_t ip_addr[16], const uint8_t ml_eid[8]) 00285 { 00286 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00287 if (!cur) { 00288 return; 00289 } 00290 00291 /* Processing for ourselves - if we have the address, and the ML-EID in the 00292 * message is _not_ ours, we delete. 00293 */ 00294 if_address_entry_t *addr_entry = addr_get_entry(cur, ip_addr); 00295 if (addr_entry && memcmp(ml_eid, cur->iid_slaac, 8)) { 00296 addr_duplicate_detected(cur, ip_addr); 00297 thread_extension_address_generate(cur); 00298 } 00299 00300 /* Scan IPv6 neighbour cache for registered entries of children */ 00301 ns_list_foreach_safe(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) { 00302 if (n->type == IP_NEIGHBOUR_REGISTERED && addr_ipv6_equal(n->ip_address, ip_addr)) { 00303 uint8_t child_mleid[8]; 00304 mac_neighbor_table_entry_t *child = thread_nd_child_mleid_get(cur, &n->ll_address[2], child_mleid); 00305 /* If this address belongs to an RFD child, with a different ML-EID, we must send it a duplicate message, and remove the EID */ 00306 if (child && memcmp(child_mleid, ml_eid, 8)) { 00307 uint8_t child_ml_addr[16]; 00308 thread_addr_write_mesh_local_16(child_ml_addr, child->mac16 , cur->thread_info); 00309 tr_warn("Forwarding address error to child %04x", common_read_16_bit(&n->ll_address[2])); 00310 thread_resolution_client_address_error(interface_id, child_ml_addr, ip_addr, ml_eid); 00311 ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, n); 00312 } 00313 } 00314 } 00315 00316 return; 00317 } 00318 00319 /* Flush neighbour cache entries pointing at this 16-bit address, or (optionally) its children */ 00320 void thread_nd_flush_neighbour_cache_for_short_addr(protocol_interface_info_entry_t *cur, uint16_t flushee, bool children) 00321 { 00322 ns_list_foreach_safe(ipv6_neighbour_t, entry, &cur->ipv6_neighbour_cache.list) { 00323 if (entry->ll_type != ADDR_802_15_4_SHORT || entry->type != IP_NEIGHBOUR_GARBAGE_COLLECTIBLE) { 00324 continue; 00325 } 00326 00327 uint16_t n16 = common_read_16_bit(entry->ll_address + 2); 00328 if (flushee == n16 || (children && flushee == thread_router_addr_from_addr(n16))) { 00329 ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, entry); 00330 } 00331 } 00332 } 00333 00334 static buffer_t *thread_nd_icmp_error_to_mesh_originator(buffer_t *buf, protocol_interface_info_entry_t *cur, const sockaddr_t *ll_src) 00335 { 00336 /* First generate a normal ICMP error (to the IP source) */ 00337 buf = icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_NO_ROUTE, 0); 00338 if (!buf) { 00339 return NULL; 00340 } 00341 00342 /* Now the messed-up bit. The source gets nothing. This is going to the mesh originator */ 00343 /* DST = ML16 derived from the mesh originator address */ 00344 memcpy(buf->dst_sa .address , cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 8); 00345 memcpy(buf->dst_sa .address + 8, ADDR_SHORT_ADR_SUFFIC, 6); 00346 buf->dst_sa .address [14] = ll_src->address [2]; 00347 buf->dst_sa .address [15] = ll_src->address [3]; 00348 /* Want 16-bit ML16 source - this should select it if available */ 00349 const uint8_t *src = addr_select_source(cur, buf->dst_sa .address , SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT); 00350 if (!src) { 00351 return buffer_free(buf); 00352 } 00353 memcpy(buf->src_sa .address , src, 16); 00354 00355 return buffer_free_route(buf); 00356 } 00357 00358 /* Called when link layer passes up a unicast packet that was not for our 00359 * link-layer address. Our mesh handlers do this when they see a packet 00360 * addressed to a non-existent child or minimal function device child. 00361 */ 00362 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) 00363 { 00364 /* If snooping, security check hasn't happened yet */ 00365 if (buf->options .ll_security_bypass_rx ) { 00366 return buffer_free(buf); 00367 } 00368 00369 /* We just drop it if it wasn't mesh-addressed (impossible) */ 00370 if (!(buf->options .lowpan_mesh_rx && ll_src->addr_type == ADDR_802_15_4_SHORT )) { 00371 return buffer_free(buf); 00372 } 00373 00374 if (!mac_neighbor_table_address_discover(mac_neighbor_info(cur), &ll_dst->address [2], ADDR_802_15_4_SHORT )) { 00375 /* We now know this was a packet for a non-existent child */ 00376 goto bounce; 00377 } 00378 00379 /* Packet must have been mesh-addressed to a minimal-function child. This always */ 00380 /* indicates a cache error, unless the IP destination was an ML16 (RLOC16). */ 00381 if (!thread_addr_is_mesh_local_16(buf->dst_sa .address , cur) || 00382 buf->dst_sa .address [14] != ll_dst->address [2] || 00383 buf->dst_sa .address [15] != ll_dst->address [3]) { 00384 goto bounce; 00385 } 00386 00387 /* Forward the packet according to IP destination - we've consistency checked 00388 * it is an ML16 matching the original mesh destination, so will get there fine. */ 00389 buf->options .ll_not_ours_rx = false; 00390 return buf; 00391 00392 bounce: 00393 *bounce = true; 00394 return thread_nd_icmp_error_to_mesh_originator(buf, cur, ll_src); 00395 } 00396 00397 /* Called when we've determined the packet isn't IP addressed to us, but has okay 00398 * security. Precedes any other checks like forwarding enabled, or destination 00399 * type, scope. 00400 */ 00401 buffer_t *thread_nd_special_forwarding(protocol_interface_info_entry_t *cur, buffer_t *buf, const sockaddr_t *ll_src, bool *bounce) 00402 { 00403 /* Funny Thread rule 00404 * 00405 * A cache error is detected if a device receives a packet containing 00406 * a 6LoWPAN mesh header[1] and an EID destination IPv6 address where 00407 * the mesh destination is the device's RLOC16 address [2] but the EID 00408 * does not belong to the receiver or, if the receiver is a router, 00409 * the EID has not been registered by any Child of the receiver. 00410 * 00411 * When a cache error is detected, the receiving device must respond by 00412 * sending an ICMPv6 Destination Unreachable message with the ICMPv6 00413 * Code set to 0 (No route to destination) [3] to the packet's mesh source 00414 * 00415 * Return "No route" if on-link destination, received from mesh, and it's not 00416 * for us or a child. Note that we return this even if not a router; 00417 * normally hosts should silently drop wrongly-addressed packets. 00418 * 00419 * (If the addressed child doesn't exist at all, the packet gets sent to 00420 * thread_nd_snoop, generating an error there). 00421 * 00422 * XXX [1] Neighbouring routers optimise out the mesh header, breaking this 00423 * response. 00424 * 00425 * XXX [1b] Children also optimise out mesh headers, so a full-function child 00426 * that has a stale resolution of a minimal device to our router address needs 00427 * to get a failure response. 00428 * 00429 * XXX [2] Mesh destination may have been RLOC16 of a child, and we have snooped 00430 * because they're MTD. 00431 * 00432 * XXX [3] "No route (0)" is a silly choice of code; "address unreachable (3)" 00433 * would make more sense. 00434 */ 00435 00436 if (ll_src->addr_type != ADDR_802_15_4_SHORT ) { 00437 return buf; 00438 } 00439 00440 mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur), &ll_src->address [2], ADDR_802_15_4_SHORT ); 00441 00442 /* Due to note 1 and 1b above, full-function children / neighbor routers 00443 * who did resolve to an RLOC16 may have optimised out the mesh header. 00444 * So we check for either the mesh header being present, or it coming 00445 * from a full-function device (FFD) neighbor. 00446 * 00447 * (If it comes from a MTD child without a mesh header we always 00448 * forward as normal, attempting address resolution if necessary. 00449 * If it comes from a child with a mesh header and the IP destination 00450 * is not in our neighbour cache, we need to send the child an error 00451 * to clear its cache.) 00452 */ 00453 if (!(buf->options .lowpan_mesh_rx || (entry && entry->ffd_device ))) { 00454 return buf; 00455 } 00456 00457 /* Link-local and ML16 addresses are not EIDs, so no error generation */ 00458 if (addr_is_ipv6_link_local(buf->dst_sa .address ) || thread_addr_is_mesh_local_16(buf->dst_sa .address , cur)) { 00459 return buf; 00460 } 00461 00462 buffer_routing_info_t *route = ipv6_buffer_route(buf); 00463 if (!route) { 00464 return buf; 00465 } 00466 00467 if (route->route_info.interface_id != cur->id) { 00468 return buf; 00469 } 00470 00471 /* On-link test - only perform this check for on-link prefixes - those will have next_hop == destination */ 00472 /* Being on-link is what tells us an address is an "EID" rather than an arbitrary global IPv6 address */ 00473 if (!addr_ipv6_equal(route->route_info.next_hop_addr, buf->dst_sa .address )) { 00474 return buf; 00475 } 00476 00477 /* If it was addressed to us as an IP router, it's okay if the packet is for a child */ 00478 if (thread_i_am_router(cur)) { 00479 //Check Registered Addresses 00480 ns_list_foreach(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) { 00481 if (n->type == IP_NEIGHBOUR_REGISTERED 00482 && memcmp(n->ip_address, buf->dst_sa .address , 16) == 0) { 00483 return buf; 00484 } 00485 } 00486 } 00487 00488 *bounce = true; 00489 return thread_nd_icmp_error_to_mesh_originator(buf, cur, ll_src); 00490 } 00491 00492 /* The handler for the packets transmitted above (draft-kelsey-thread-network-data-00) */ 00493 buffer_t *thread_nd_icmp_handler(protocol_interface_info_entry_t *cur, buffer_t *buf, bool *bounce) 00494 { 00495 (void) bounce; 00496 /* Try to make sure we specifically "such an ICMP message", not normal ones */ 00497 if (!thread_addr_is_mesh_local_16(buf->dst_sa .address , cur) || !thread_addr_is_mesh_local_16(buf->src_sa .address , cur)) { 00498 return buf; 00499 } 00500 00501 if (buf->options .type != ICMPV6_TYPE_ERROR_DESTINATION_UNREACH) { 00502 return buf; 00503 } 00504 00505 if (buf->options .code != ICMPV6_CODE_DST_UNREACH_NO_ROUTE) { 00506 return buf; 00507 } 00508 00509 /* Make sure we have the original destination address from invoking packet */ 00510 if (buffer_data_length(buf) < 4 + 40) { 00511 return buf; 00512 } 00513 00514 const uint8_t *targetIP = buffer_data_pointer(buf) + 4 + 24; 00515 00516 /* Try to look up the ML64 entry in the cache. */ 00517 ipv6_neighbour_t *n = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, targetIP); 00518 if (!n || n->ll_type != ADDR_802_15_4_SHORT || n->type != IP_NEIGHBOUR_GARBAGE_COLLECTIBLE) { 00519 return buf; 00520 } 00521 00522 /* Invalidate that ML64 entry if its 16-bit address is equal to, or a child 00523 * of, the source of the ICMP message. If it doesn't match, suggests 00524 * a bogus packet - exit now. 00525 */ 00526 uint16_t icmp16 = common_read_16_bit(buf->src_sa .address + 14); 00527 uint16_t entry16 = common_read_16_bit(n->ll_address + 2); 00528 if (!thread_addr_is_equal_or_child(icmp16, entry16)) { 00529 return buf; 00530 } 00531 00532 ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, n); 00533 00534 return buf; 00535 } 00536 00537 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) 00538 { 00539 ipv6_neighbour_t *neigh; 00540 uint8_t ll_address[4]; 00541 bool neighbor_created = false; 00542 common_write_16_bit(panId, ll_address + 0); 00543 common_write_16_bit(mac16, ll_address + 2); 00544 neigh = ipv6_neighbour_lookup_or_create(&cur->ipv6_neighbour_cache, ipv6Address); 00545 if (!neigh) { 00546 return -1; 00547 } 00548 00549 uint8_t *nce_eui64 = ipv6_neighbour_eui64(&cur->ipv6_neighbour_cache, neigh); 00550 if (neigh->state != IP_NEIGHBOUR_NEW && memcmp(nce_eui64, mac64, 8) != 0) 00551 { 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 int thread_nd_map_anycast_address(protocol_interface_info_entry_t *cur, uint16_t *addr16) 00581 { 00582 // Nothing implemented for now 00583 uint16_t anycastAddress = *addr16; 00584 if(anycastAddress == 0xfc00) { 00585 // this is leader anycast address 00586 *addr16 = thread_router_addr_from_id(cur->thread_info->thread_leader_data->leaderRouterId); 00587 return 0; 00588 } 00589 if ((anycastAddress & 0xfff0) == 0xfc00) { 00590 // Check DHCPv6 anycast address mapping 00591 uint8_t context = anycastAddress; 00592 if (thread_nd_dhcp_anycast_address_mapping_from_network_data(&cur->thread_info->networkDataStorage, addr16, context)) { 00593 return 0; 00594 } 00595 } 00596 00597 if ((anycastAddress & 0xfff0) == 0xfc10 || (anycastAddress & 0xfff0) == 0xfc20) { 00598 // service mapping to anycast address 00599 uint8_t S_id = anycastAddress & 0x0f; 00600 if (thread_nd_service_anycast_address_mapping_from_network_data(&cur->thread_info->networkDataStorage, addr16, S_id)) { 00601 return 0; 00602 } 00603 } 00604 00605 if ((anycastAddress & 0xfff8) == 0xfc30) { 00606 // Commissioner anycast address mapping 00607 if (!cur->thread_info->registered_commissioner.commissioner_valid) { 00608 return -1; 00609 } 00610 if ( (anycastAddress & 0x0007) != cur->thread_info->registered_commissioner.session_id % 8 ) { 00611 return -1; 00612 } 00613 *addr16 = common_read_16_bit(cur->thread_info->registered_commissioner.border_router_address + 14); 00614 return 0; 00615 } 00616 if (thread_extension_aloc_map(cur,addr16)) { 00617 return 0; 00618 } 00619 00620 return -1; 00621 } 00622 00623 #endif //HAVE_THREAD_NEIGHBOR_DISCOVERY 00624 #endif //HAVE_THREAD 00625
Generated on Tue Aug 9 2022 00:37:23 by
1.7.2