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