BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 12 2022 12:22:25 by
