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.
ipv6_resolution.c
00001 /* 00002 * Copyright (c) 2015-2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "nsconfig.h" 00019 #include "string.h" 00020 #include "ns_types.h" 00021 #include "ns_list.h" 00022 #include "ns_trace.h" 00023 #include "nsdynmemLIB.h" 00024 #include "Core/include/socket.h" 00025 #include "NWK_INTERFACE/Include/protocol.h" 00026 #include "Common_Protocols/ipv6.h" 00027 #include "Common_Protocols/icmpv6.h" 00028 #include "Common_Protocols/icmpv6_prefix.h" 00029 #include "Common_Protocols/icmpv6_radv.h" 00030 #include "Common_Protocols/udp.h" 00031 #include "6LoWPAN/ND/nd_router_object.h" // for gp_address_ functions - better place? 00032 #include "ipv6_stack/ipv6_routing_table.h" 00033 #include "ipv6_stack/protocol_ipv6.h" 00034 #include "Common_Protocols/ipv6_resolution.h" 00035 #include "Common_Protocols/tcp.h" 00036 #include "Service_Libs/whiteboard/whiteboard.h" 00037 #include "Service_Libs/etx/etx.h" 00038 #include "platform/arm_hal_interrupt.h" 00039 #include "common_functions.h" 00040 00041 #define TRACE_GROUP "ip6r" 00042 00043 #ifndef RESOLUTION_QUEUE_LIMIT 00044 #define RESOLUTION_QUEUE_LIMIT 2 00045 #endif 00046 00047 void ipv6_interface_resolve_send_ns(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, bool unicast, uint_fast8_t seq) 00048 { 00049 protocol_interface_info_entry_t *cur_interface = NS_CONTAINER_OF(cache, protocol_interface_info_entry_t, ipv6_neighbour_cache); 00050 00051 if (cur_interface->if_ns_transmit) { 00052 /* Thread uses DHCP Leasequery (!) instead of NS for address resolution */ 00053 /* We still allow unicast NUD probes using NS, although I expect them to be disabled */ 00054 if (cur_interface->if_ns_transmit(cur_interface, entry, unicast, seq)) { 00055 return; 00056 } 00057 } 00058 00059 #ifdef HAVE_IPV6_ND 00060 tr_debug("Sending %s NS for: %s", 00061 (unicast ? "unicast" : "multicast"), trace_ipv6(entry->ip_address)); 00062 00063 buffer_t *prompting_packet = ns_list_get_first(&entry->queue); 00064 buffer_t *buf = icmpv6_build_ns(cur_interface, entry->ip_address, 00065 prompting_packet ? prompting_packet->src_sa .address : NULL, 00066 unicast, false, NULL); 00067 protocol_push(buf); 00068 #else 00069 tr_error("No NS handler for interface %d", cur_interface->id); 00070 #endif 00071 } 00072 00073 /* Entry has already been removed from cache, and is about to be freed. Hence entry->queue can't change while we process it */ 00074 void ipv6_interface_resolution_failed(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry) 00075 { 00076 protocol_interface_info_entry_t *cur_interface = NS_CONTAINER_OF(cache, protocol_interface_info_entry_t, ipv6_neighbour_cache); 00077 00078 tr_warn("LL addr of %s not found", trace_ipv6(entry->ip_address)); 00079 ns_list_foreach_safe(buffer_t, buf, &entry->queue) { 00080 ns_list_remove(&entry->queue, buf); 00081 uint8_t code; 00082 if (buf->options.ip_extflags & IPEXT_SRH_RPL) { 00083 /* Note that as the border router we loopback SRH errors to ourselves if the first hop doesn't resolve */ 00084 code = ICMPV6_CODE_DST_UNREACH_SRC_RTE_HDR_ERR; 00085 } else { 00086 code = ICMPV6_CODE_DST_UNREACH_ADDR_UNREACH; 00087 } 00088 /* XXX note no special handling for our own socket transmissions, 00089 * unlike original case. If we want this, we should do it in ICMP 00090 * RX handling, so we get events for external errors. 00091 */ 00092 buf = socket_tx_buffer_event(buf, SOCKET_NO_ROUTE); 00093 if (buf) { 00094 buf = icmpv6_error(buf, cur_interface, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, code, 0); 00095 protocol_push(buf); 00096 } 00097 } 00098 } 00099 00100 /* Silly bit of interface glue - ipv6_routing_table.c doesn't know about interface structures, 00101 * but it needs to be able to get from the interface id in the Routing Table and/or 00102 * Destination Cache to the relevant Neighbour Cache 00103 */ 00104 ipv6_neighbour_cache_t *ipv6_neighbour_cache_by_interface_id(int8_t interface_id) 00105 { 00106 protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(interface_id); 00107 00108 return interface ? &interface->ipv6_neighbour_cache : NULL; 00109 } 00110 00111 void ipv6_send_queued(ipv6_neighbour_t *entry) 00112 { 00113 ns_list_foreach_safe(buffer_t, buf, &entry->queue) { 00114 ns_list_remove(&entry->queue, buf); 00115 tr_debug("Destination solved"); 00116 protocol_push(buf); 00117 } 00118 } 00119 00120 static void ipv6_trigger_resolve_query(protocol_interface_info_entry_t *cur_interface, buffer_t *buf, ipv6_neighbour_t *n) 00121 { 00122 if (n->state != IP_NEIGHBOUR_NEW && n->state != IP_NEIGHBOUR_INCOMPLETE) { 00123 tr_debug("ipv6_resolve_query"); 00124 buffer_free(buf); 00125 return; 00126 } 00127 00128 uint_fast16_t count = ns_list_count(&n->queue); 00129 while (count >= RESOLUTION_QUEUE_LIMIT) { 00130 buffer_t *b = ns_list_get_first(&n->queue); 00131 ns_list_remove(&n->queue, b); 00132 socket_tx_buffer_event_and_free(b, SOCKET_NO_ROUTE); 00133 count--; 00134 } 00135 tr_debug("Queueing for: %s", trace_ipv6(n->ip_address)); 00136 ns_list_add_to_end(&n->queue, buf); 00137 00138 if (n->state == IP_NEIGHBOUR_NEW) { 00139 /* Start NS timers, send first NS */ 00140 ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, n, IP_NEIGHBOUR_INCOMPLETE); 00141 ipv6_interface_resolve_send_ns(&cur_interface->ipv6_neighbour_cache, n, false, 0); 00142 } 00143 00144 } 00145 00146 00147 /* Given a buffer with IP next-hop address and outgoing interface, find the 00148 * neighbour entry, and if complete, write the link-layer address into the buffer 00149 * destination, and return the Neighbour Cache entry. 00150 * If we have an incomplete Neighbour Cache entry, start address resolution 00151 * and queue the buffer, returning NULL. 00152 */ 00153 ipv6_neighbour_t *ipv6_interface_resolve_new(protocol_interface_info_entry_t *cur, buffer_t *buf) 00154 { 00155 buffer_routing_info_t *route = ipv6_buffer_route(buf); 00156 if (!route) { 00157 tr_warn("XXX ipv6_interface_resolve no route!"); 00158 // Can this happen? How did it get to this interface in the first place? 00159 // If it can happen, send ICMP Destination Unreachable 00160 buffer_free(buf); 00161 return NULL; 00162 } 00163 ipv6_neighbour_t *n = ipv6_neighbour_lookup_or_create(&cur->ipv6_neighbour_cache, route->route_info.next_hop_addr); 00164 if (!n) { 00165 // If it can happen, send ICMP Destination Unreachable 00166 tr_warn("No heap for address resolve"); 00167 buffer_free(buf); 00168 return NULL; 00169 } 00170 00171 if (n->state == IP_NEIGHBOUR_NEW || n->state == IP_NEIGHBOUR_INCOMPLETE) { 00172 addrtype_t ll_type; 00173 const uint8_t *ll_addr; 00174 00175 if (cur->if_map_ip_to_link_addr && 00176 cur->if_map_ip_to_link_addr(cur, route->route_info.next_hop_addr, &ll_type, &ll_addr)) { 00177 ipv6_neighbour_update_from_na(&cur->ipv6_neighbour_cache, n, NA_O, ll_type, ll_addr); 00178 } 00179 } 00180 00181 if (n->state == IP_NEIGHBOUR_NEW || n->state == IP_NEIGHBOUR_INCOMPLETE) { 00182 ipv6_trigger_resolve_query(cur, buf, n); 00183 return NULL; 00184 } 00185 00186 buf->dst_sa .addr_type = n->ll_type; 00187 memcpy(buf->dst_sa .address , n->ll_address, addr_len_from_type(n->ll_type)); 00188 00189 /* Optimisation trick - if security bypass is set, this is presumably some 00190 * sort of MLE-type link management packet. Not worth sending extra NS/NA 00191 * noise for these. 00192 */ 00193 if (!(buf->options .ll_security_bypass_tx && addr_is_ipv6_link_local(route->route_info.next_hop_addr))) { 00194 n = ipv6_neighbour_used(&cur->ipv6_neighbour_cache, n); 00195 } 00196 return n; 00197 } 00198 00199 /* Attempt a mapping from current information (neighbour cache, hard mappings) */ 00200 bool ipv6_map_ip_to_ll(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *n, const uint8_t ip_addr[16], addrtype_t *ll_type, const uint8_t **ll_addr_out) 00201 { 00202 if (!n) { 00203 n = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, ip_addr); 00204 } 00205 if (n && !(n->state == IP_NEIGHBOUR_NEW || n->state == IP_NEIGHBOUR_INCOMPLETE)) { 00206 *ll_type = n->ll_type; 00207 *ll_addr_out = n->ll_address; 00208 return true; 00209 } 00210 00211 if (cur->if_map_ip_to_link_addr && 00212 cur->if_map_ip_to_link_addr(cur, ip_addr, ll_type, ll_addr_out)) { 00213 return true; 00214 } 00215 00216 return false; 00217 } 00218 00219 /* Attempt a mapping from current information (neighbour cache, hard mappings) */ 00220 bool ipv6_map_ll_to_ip_link_local(protocol_interface_info_entry_t *cur, addrtype_t ll_type, const uint8_t *ll_addr, uint8_t ip_addr_out[16]) 00221 { 00222 if (cur->if_map_link_addr_to_ip && 00223 cur->if_map_link_addr_to_ip(cur, ll_type, ll_addr, ip_addr_out)) { 00224 return true; 00225 } 00226 00227 ns_list_foreach(ipv6_neighbour_t, n, &cur->ipv6_neighbour_cache.list) { 00228 if (ipv6_neighbour_ll_addr_match(n, ll_type, ll_addr) && addr_is_ipv6_link_local(n->ip_address)) { 00229 memcpy(ip_addr_out, n->ip_address, 16); 00230 return true; 00231 } 00232 } 00233 00234 return false; 00235 } 00236 00237 /* To comply with ETX returns 0xFFFF when neighbor doesn't exist and 0 when neighbor is currently unknown. */ 00238 uint16_t ipv6_map_ip_to_ll_and_call_ll_addr_handler(protocol_interface_info_entry_t *cur, int8_t interface_id, ipv6_neighbour_t *n, const uint8_t ipaddr[16], ll_addr_handler_t *ll_addr_handler_ptr) 00239 { 00240 addrtype_t ll_type; 00241 const uint8_t *ll_addr; 00242 00243 if (!cur) { 00244 cur = protocol_stack_interface_info_get_by_id(interface_id); 00245 if (!cur) { 00246 return 0xFFFF; 00247 } 00248 } 00249 00250 if (!ipv6_map_ip_to_ll(cur, n, ipaddr, &ll_type, &ll_addr)) { 00251 return 0; 00252 } 00253 00254 return ll_addr_handler_ptr(cur->id, ll_type, ll_addr); 00255 }
Generated on Tue Jul 12 2022 12:44:26 by
