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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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
Generated on Tue Jul 12 2022 13:54:59 by
