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.
address.c
00001 /* 00002 * Copyright (c) 2008, 2010-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 * \file address.c 00019 * \brief Utility functions concernig addresses 00020 * 00021 * This file contains all the utility functions that can be used to 00022 * check, manipulate etc. addresses. 00023 */ 00024 #include "nsconfig.h" 00025 #include "ns_types.h" 00026 #include "ip6string.h" 00027 #include "ns_trace.h" 00028 #include "randLIB.h" 00029 #include "string.h" 00030 #include "nsdynmemLIB.h" 00031 #include "ns_sha256.h" 00032 #include "socket_api.h" 00033 #include "Common_Protocols/ipv6_constants.h" 00034 #include "Common_Protocols/icmpv6.h" 00035 #include "Common_Protocols/mld.h" 00036 #include "6LoWPAN/Thread/thread_common.h" 00037 #include "common_functions.h" 00038 00039 #include "RPL/rpl_control.h" 00040 00041 #define TRACE_GROUP "addr" 00042 00043 typedef struct addr_notification { 00044 if_address_notification_fn *fn; 00045 ns_list_link_t link; 00046 } addr_notification_t; 00047 00048 static NS_LIST_DEFINE(addr_notifications, addr_notification_t, link); 00049 00050 typedef struct addr_policy_table_entry_t { 00051 uint8_t prefix[16]; 00052 uint8_t prefix_len; 00053 uint8_t precedence; 00054 uint8_t label; 00055 ns_list_link_t link; 00056 } addr_policy_table_entry_t; 00057 00058 static NS_LIST_DEFINE(addr_policy_table, addr_policy_table_entry_t, link); 00059 00060 uint32_t addr_preferences_default = SOCKET_IPV6_PREFER_SRC_TMP | SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00061 00062 static void addr_policy_table_reset(void); 00063 static void addr_max_entries_check(protocol_interface_info_entry_t *cur, if_address_source_t source); 00064 00065 const uint8_t ADDR_LINK_LOCAL_PREFIX[8] = { 0xfe, 0x80 }; 00066 const uint8_t ADDR_SHORT_ADR_SUFFIC[6] = { 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00}; 00067 00068 const uint8_t ADDR_MULTICAST_SOLICITED[13] = { 0xff, 0x02, [11] = 0x01, 0xff}; 00069 const uint8_t ADDR_IF_LOCAL_ALL_NODES[16] = { 0xff, 0x01, [15] = 0x01 }; 00070 const uint8_t ADDR_IF_LOCAL_ALL_ROUTERS[16] = { 0xff, 0x01, [15] = 0x02 }; 00071 const uint8_t ADDR_LINK_LOCAL_ALL_NODES[16] = { 0xff, 0x02, [15] = 0x01 }; 00072 const uint8_t ADDR_LINK_LOCAL_ALL_ROUTERS[16] = { 0xff, 0x02, [15] = 0x02 }; 00073 const uint8_t ADDR_LINK_LOCAL_ALL_MLDV2_ROUTERS[16] = { 0xff, 0x02, [15] = 0x16 }; 00074 const uint8_t ADDR_LINK_LOCAL_MDNS[16] = { 0xff, 0x02, [15] = 0xfb }; 00075 const uint8_t ADDR_REALM_LOCAL_ALL_NODES[16] = { 0xff, 0x03, [15] = 0x01 }; 00076 const uint8_t ADDR_REALM_LOCAL_ALL_ROUTERS[16] = { 0xff, 0x03, [15] = 0x02 }; 00077 const uint8_t ADDR_SITE_LOCAL_ALL_ROUTERS[16] = { 0xff, 0x05, [15] = 0x02 }; 00078 const uint8_t ADDR_ALL_MPL_FORWARDERS[16] = { 0xff, 0x03, [15] = 0xfc }; 00079 const uint8_t ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS[16] = { 0xff, 0x02, [13] = 0x01, 0x00, 0x02 }; 00080 00081 const uint8_t ADDR_IPV4_MAPPED_PREFIX[12] = { [10] = 0xff, 0xff }; 00082 const uint8_t ADDR_LOOPBACK[16] = { [15] = 1 }; 00083 const uint8_t ADDR_UNSPECIFIED[16] = { 0 }; /* Note a few bits of code check for pointer equality with ADDR_UNSPECIFIED */ 00084 #define ADDR_IPV4_COMPATIBLE ADDR_LOOPBACK /* First 96 bits match...*/ 00085 00086 #define ADDR_MULTICAST_LINK_PREFIX ADDR_LINK_LOCAL_ALL_NODES /* ff02::xx */ 00087 #define ADDR_MULTICAST_REALM_PREFIX ADDR_ALL_MPL_FORWARDERS /* ff03::xx */ 00088 00089 static const uint8_t *addr_iid_secret_key; 00090 static const uint8_t *addr_initial_iid; 00091 static uint8_t addr_iid_secret_key_len; 00092 00093 static bool addr_am_implicit_group_member(const uint8_t group[static 16]) 00094 { 00095 static const uint8_t * const implicit_groups[] = { 00096 ADDR_LINK_LOCAL_ALL_NODES, 00097 ADDR_IF_LOCAL_ALL_NODES, 00098 }; 00099 00100 for (uint_fast8_t i = 0; i < sizeof implicit_groups / sizeof implicit_groups[0]; i++) { 00101 if (addr_ipv6_equal(implicit_groups[i], group)) { 00102 return true; 00103 } 00104 } 00105 return false; 00106 } 00107 00108 uint8_t addr_len_from_type(addrtype_t addr_type) 00109 { 00110 switch (addr_type) { 00111 case ADDR_NONE : 00112 return 0; 00113 case ADDR_802_15_4_SHORT : 00114 return 2 + 2; /* Some users don't have the PAN ID */ 00115 case ADDR_802_15_4_LONG : 00116 return 2 + 8; 00117 case ADDR_EUI_48 : 00118 return 6; 00119 case ADDR_IPV6 : 00120 return 16; 00121 case ADDR_BROADCAST : 00122 return 0; /* Don't really handle this */ 00123 } 00124 return 0; 00125 } 00126 00127 /** 00128 * Check if an address is a broadcast address 00129 * 00130 * \param addr pointer to an address_t containing the address to be checked 00131 * \param addr_type the type of the address_t 00132 * \return 0 if the address is a broadcast address 00133 */ 00134 uint8_t addr_check_broadcast(const address_t addr, addrtype_t addr_type) 00135 { 00136 switch (addr_type) { 00137 case ADDR_802_15_4_SHORT : 00138 break; 00139 case ADDR_BROADCAST : 00140 return 0; 00141 default: 00142 return 1; 00143 } 00144 00145 uint8_t size = 2; 00146 uint8_t *ptr = (uint8_t *) addr; 00147 ptr += 2; 00148 00149 while (size) { 00150 if ((*ptr++) != 0xFF) { 00151 break; 00152 } else { 00153 size--; 00154 } 00155 } 00156 return (size); 00157 00158 } 00159 00160 bool addr_is_ipv6_link_local(const uint8_t addr[static 16]) 00161 { 00162 return addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80; 00163 } 00164 00165 /* Site-local addresses deprecated, but still processed by RFC 6724 address selection */ 00166 static bool addr_is_ipv6_site_local(const uint8_t addr[static 16]) 00167 { 00168 return addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0; 00169 } 00170 00171 static bool addr_is_ipv4_mapped(const uint8_t addr[static 16]) 00172 { 00173 return memcmp(addr, ADDR_IPV4_MAPPED_PREFIX, 12) == 0; 00174 } 00175 00176 /* Scope(A), as defined in RFC 6724 plus RFC 4007 */ 00177 uint_fast8_t addr_ipv6_scope(const uint8_t addr[static 16], const protocol_interface_info_entry_t *interface) 00178 { 00179 if (addr_is_ipv6_multicast(addr)) { 00180 return addr_ipv6_multicast_scope(addr); 00181 } 00182 if (addr_is_ipv6_link_local(addr) || addr_is_ipv6_loopback(addr)) { 00183 return IPV6_SCOPE_LINK_LOCAL; 00184 } 00185 if (addr_is_ipv6_site_local(addr)) { 00186 return IPV6_SCOPE_SITE_LOCAL; 00187 } 00188 /* Thread-specific hack - we want to treat one specific "mesh local" ULA as 00189 * "realm local" scope. (This is necessary, for example, to use a 00190 * mesh-local ULA address as source when sending realm-local multicast). 00191 */ 00192 if (thread_addr_is_mesh_local(addr, interface)) { 00193 return IPV6_SCOPE_REALM_LOCAL; 00194 } 00195 if (addr_is_ipv4_mapped(addr)) { 00196 if ((addr[12] == 169 && addr[13] == 254) || addr[12] == 127) { 00197 return IPV6_SCOPE_LINK_LOCAL; 00198 } 00199 return IPV6_SCOPE_GLOBAL; 00200 } 00201 return IPV6_SCOPE_GLOBAL; 00202 } 00203 00204 void address_module_init(void) 00205 { 00206 addr_policy_table_reset(); 00207 //mac_reset_short_address(); 00208 } 00209 00210 #ifdef MULTICAST_FORWARDING 00211 static if_group_fwd_entry_t *addr_multicast_fwd_list_lookup(if_group_fwd_list_t *list, const uint8_t group[16]) 00212 { 00213 ns_list_foreach(if_group_fwd_entry_t, e, list) { 00214 if (addr_ipv6_equal(e->group, group)) { 00215 return e; 00216 } 00217 } 00218 return NULL; 00219 } 00220 00221 bool addr_multicast_fwd_check(protocol_interface_info_entry_t *interface, const uint8_t group[16]) 00222 { 00223 return addr_multicast_fwd_list_lookup(&interface->ip_groups_fwd, group) != NULL; 00224 } 00225 00226 static void addr_multicast_fwd_adjust_upstream(protocol_interface_info_entry_t *downstream, protocol_interface_info_entry_t *upstream, const uint8_t group[16], bool add) 00227 { 00228 if (!upstream || downstream == upstream || !downstream->ip_multicast_forwarding) { 00229 return; 00230 } 00231 uint8_t group_scope = addr_ipv6_multicast_scope(group); 00232 if (downstream->zone_index[group_scope] == upstream->zone_index[group_scope]) { 00233 tr_debug("Multicast proxy %s %s", add ? "add" : "remove", trace_ipv6(group)); 00234 if (add) { 00235 addr_add_group(upstream, group); 00236 } else { 00237 addr_remove_group(upstream, group); 00238 } 00239 } 00240 } 00241 00242 void addr_multicast_fwd_adjust_upstream_full(protocol_interface_info_entry_t *upstream, bool add) 00243 { 00244 ns_list_foreach(protocol_interface_info_entry_t, interface, &protocol_interface_info_list) { 00245 ns_list_foreach(if_group_fwd_entry_t, group, &interface->ip_groups_fwd) { 00246 addr_multicast_fwd_adjust_upstream(interface, upstream, group->group, add); 00247 } 00248 } 00249 } 00250 00251 void addr_multicast_fwd_set_forwarding(struct protocol_interface_info_entry *interface, bool enable) 00252 { 00253 /* Do nothing if enable state isn't changing */ 00254 if (interface->ip_multicast_forwarding == enable) { 00255 return; 00256 } 00257 00258 /* If we disable forwarding on upstream, clear it out to avoid maintenance confusion */ 00259 if (!enable && interface == protocol_core_multicast_upstream) { 00260 multicast_fwd_set_proxy_upstream(-1); 00261 } 00262 00263 /* Adjust routine checks that forwarding is on before doing any processing. So make sure it's on 00264 * now, then we'll set requested state afterwards. */ 00265 interface->ip_multicast_forwarding = true; 00266 00267 /* Add or remove all groups on changing downstream interface to upstream */ 00268 if (protocol_core_multicast_upstream) { 00269 ns_list_foreach(if_group_fwd_entry_t, group, &interface->ip_groups_fwd) { 00270 addr_multicast_fwd_adjust_upstream(interface, protocol_core_multicast_upstream, group->group, enable); 00271 } 00272 } 00273 00274 interface->ip_multicast_forwarding = enable; 00275 } 00276 00277 bool addr_multicast_fwd_add(protocol_interface_info_entry_t *interface, const uint8_t group[16], uint32_t lifetime) 00278 { 00279 if_group_fwd_entry_t *entry = addr_multicast_fwd_list_lookup(&interface->ip_groups_fwd, group); 00280 if (entry) { 00281 if (entry->lifetime < lifetime) { 00282 entry->lifetime = lifetime; 00283 } 00284 return true; 00285 } 00286 entry = ns_dyn_mem_alloc(sizeof *entry); 00287 if (!entry) { 00288 return false; 00289 } 00290 memcpy(entry->group, group, 16); 00291 ns_list_add_to_end(&interface->ip_groups_fwd, entry); 00292 addr_multicast_fwd_adjust_upstream(interface, protocol_core_multicast_upstream, group, true); 00293 entry->lifetime = lifetime; 00294 tr_debug("MC fwd added to IF %d: %s", interface->id, trace_ipv6(group)); 00295 return true; 00296 } 00297 00298 static void addr_multicast_fwd_delete_entry(protocol_interface_info_entry_t *interface, if_group_fwd_entry_t *entry) 00299 { 00300 addr_multicast_fwd_adjust_upstream(interface, protocol_core_multicast_upstream, entry->group, false); 00301 ns_list_remove(&interface->ip_groups_fwd, entry); 00302 ns_dyn_mem_free(entry); 00303 } 00304 00305 bool addr_multicast_fwd_remove(protocol_interface_info_entry_t *interface, const uint8_t group[16]) 00306 { 00307 if_group_fwd_entry_t *entry = addr_multicast_fwd_list_lookup(&interface->ip_groups_fwd, group); 00308 if (!entry) { 00309 return false; 00310 } 00311 00312 tr_debug("MC fwd removed from IF %d: %s", interface->id, trace_ipv6(group)); 00313 addr_multicast_fwd_delete_entry(interface, entry); 00314 00315 return true; 00316 } 00317 #endif // MULTICAST_FORWARDING 00318 00319 int_fast8_t addr_policy_table_add_entry(const uint8_t *prefix, uint8_t len, uint8_t precedence, uint8_t label) 00320 { 00321 addr_policy_table_entry_t *entry = ns_dyn_mem_alloc(sizeof(addr_policy_table_entry_t)); 00322 if (!entry) { 00323 return -1; 00324 } 00325 bitcopy(entry->prefix, prefix, len); 00326 entry->prefix_len = len; 00327 entry->precedence = precedence; 00328 entry->label = label; 00329 00330 /* Table is sorted longest-prefix-first, for longest-match searching */ 00331 bool inserted = false; 00332 ns_list_foreach(addr_policy_table_entry_t, before, &addr_policy_table) { 00333 if (before->prefix_len > len) { 00334 continue; 00335 } 00336 if (before->prefix_len == len && bitsequal(before->prefix, prefix, len)) { 00337 ns_dyn_mem_free(entry); 00338 return -2; 00339 } 00340 ns_list_add_before(&addr_policy_table, before, entry); 00341 inserted = true; 00342 break; 00343 } 00344 00345 if (!inserted) { 00346 ns_list_add_to_end(&addr_policy_table, entry); 00347 } 00348 00349 return 0; 00350 } 00351 00352 int_fast8_t addr_policy_table_delete_entry(const uint8_t *prefix, uint8_t len) 00353 { 00354 ns_list_foreach(addr_policy_table_entry_t, entry, &addr_policy_table) { 00355 if (entry->prefix_len == len && bitsequal(entry->prefix, prefix, len)) { 00356 ns_list_remove(&addr_policy_table, entry); 00357 ns_dyn_mem_free(entry); 00358 return 0; 00359 } 00360 } 00361 00362 return -1; 00363 } 00364 /// @TODO do we need this test print anymore ? 00365 void addr_policy_table_print(void) 00366 { 00367 ns_list_foreach(addr_policy_table_entry_t, entry, &addr_policy_table) { 00368 char addr[40]; 00369 ip6tos(entry->prefix, addr); 00370 tr_debug("%3d %3d %s/%u\n", entry->precedence, entry->label, addr, entry->prefix_len); 00371 } 00372 } 00373 00374 static void addr_policy_table_reset(void) 00375 { 00376 ns_list_foreach_safe(addr_policy_table_entry_t, entry, &addr_policy_table) { 00377 ns_list_remove(&addr_policy_table, entry); 00378 ns_dyn_mem_free(entry); 00379 } 00380 00381 /* Default policy table from RFC 6724 */ 00382 addr_policy_table_add_entry(ADDR_LOOPBACK, 128, 50 , 0); 00383 addr_policy_table_add_entry(NULL, 0, 40 , 1); 00384 addr_policy_table_add_entry(ADDR_IPV4_MAPPED_PREFIX, 96, 35, 4); 00385 addr_policy_table_add_entry((const uint8_t[]) { 0x20, 0x02 }, 16, 30, 2); 00386 addr_policy_table_add_entry((const uint8_t[]) { 0x20, 0x01, 0, 0 }, 32, 5, 5); 00387 addr_policy_table_add_entry((const uint8_t[]) { 0xfc }, 7, 3, 13); 00388 addr_policy_table_add_entry(ADDR_IPV4_COMPATIBLE, 96, 1, 3); 00389 addr_policy_table_add_entry((const uint8_t[]) { 0xfe, 0xc0 }, 10, 1, 11); 00390 addr_policy_table_add_entry((const uint8_t[]) { 0x3f, 0xfe }, 16, 1, 12); 00391 //addr_policy_table_print(); 00392 } 00393 00394 static const addr_policy_table_entry_t *addr_get_policy(const uint8_t addr[static 16]) 00395 { 00396 ns_list_foreach(const addr_policy_table_entry_t, entry, &addr_policy_table) { 00397 if (bitsequal(entry->prefix, addr, entry->prefix_len)) { 00398 return entry; 00399 } 00400 } 00401 00402 /* Shouldn't happen - should always have a default entry */ 00403 return NULL; 00404 } 00405 00406 /* RFC 6724 CommonPrefixLen(S, D) */ 00407 static uint_fast8_t addr_common_prefix_len(const uint8_t src[static 16], uint_fast8_t src_prefix_len, const uint8_t dst[static 16]) 00408 { 00409 uint_fast8_t common = 0; 00410 00411 while (src_prefix_len >= 8 && *src == *dst) { 00412 common += 8; 00413 src_prefix_len -= 8; 00414 ++src; 00415 ++dst; 00416 } 00417 00418 if (src_prefix_len) { 00419 uint8_t trail = common_count_leading_zeros_8(*src ^ *dst); 00420 if (trail > src_prefix_len) { 00421 trail = src_prefix_len; 00422 } 00423 common += trail; 00424 } 00425 00426 return common; 00427 } 00428 00429 if_address_entry_t *addr_get_entry(const protocol_interface_info_entry_t *interface, const uint8_t addr[static 16]) 00430 { 00431 ns_list_foreach(if_address_entry_t, entry, &interface->ip_addresses) { 00432 if (addr_ipv6_equal(entry->address, addr)) { 00433 return entry; 00434 } 00435 } 00436 00437 return NULL; 00438 } 00439 00440 bool addr_is_assigned_to_interface(const protocol_interface_info_entry_t *interface, const uint8_t addr[static 16]) 00441 { 00442 if_address_entry_t *entry = addr_get_entry(interface, addr); 00443 return entry && !entry->tentative; 00444 } 00445 00446 bool addr_is_tentative_for_interface(const protocol_interface_info_entry_t *interface, const uint8_t addr[static 16]) 00447 { 00448 if_address_entry_t *entry = addr_get_entry(interface, addr); 00449 return entry && entry->tentative; 00450 } 00451 00452 if_group_entry_t *addr_add_group(protocol_interface_info_entry_t *interface, const uint8_t group[static 16]) 00453 { 00454 if_group_entry_t *entry = addr_get_group_entry(interface, group); 00455 if (entry) { 00456 if (entry->ref_count != 0xFFFF) { 00457 entry->ref_count++; 00458 } 00459 return entry; 00460 } 00461 00462 if (!addr_is_ipv6_multicast(group)) { 00463 return NULL; 00464 } 00465 00466 if (addr_am_implicit_group_member(group)) { 00467 return NULL; 00468 } 00469 00470 entry = ns_dyn_mem_alloc(sizeof(if_group_entry_t)); 00471 if (!entry) { 00472 return NULL; 00473 } 00474 memcpy(entry->group, group, 16); 00475 entry->ref_count = 1; 00476 ns_list_add_to_end(&interface->ip_groups, entry); 00477 00478 mld_start_listening(interface, entry); 00479 00480 return entry; 00481 } 00482 00483 /* This does reference count */ 00484 void addr_remove_group(protocol_interface_info_entry_t *interface, const uint8_t group[static 16]) 00485 { 00486 if_group_entry_t *entry = addr_get_group_entry(interface, group); 00487 if (entry) { 00488 if (entry->ref_count != 0xFFFF) { 00489 if (--entry->ref_count == 0) { 00490 addr_delete_group_entry(interface, entry); 00491 } 00492 } 00493 } 00494 } 00495 00496 /* This does NOT reference count - it actually deletes the entry */ 00497 void addr_delete_group_entry(protocol_interface_info_entry_t *interface, if_group_entry_t *entry) 00498 { 00499 mld_stop_listening(interface, entry); 00500 ns_list_remove(&interface->ip_groups, entry); 00501 ns_dyn_mem_free(entry); 00502 } 00503 00504 void addr_delete_group(protocol_interface_info_entry_t *interface, const uint8_t group[static 16]) 00505 { 00506 if_group_entry_t *entry = addr_get_group_entry(interface, group); 00507 if (entry) { 00508 addr_delete_group_entry(interface, entry); 00509 } 00510 } 00511 00512 if_group_entry_t *addr_get_group_entry(const protocol_interface_info_entry_t *interface, const uint8_t group[static 16]) 00513 { 00514 ns_list_foreach(if_group_entry_t, entry, &interface->ip_groups) { 00515 if (addr_ipv6_equal(entry->group, group)) { 00516 return entry; 00517 } 00518 } 00519 00520 return NULL; 00521 } 00522 00523 static void addr_generate_solicited_node_group(uint8_t group[static 16], const uint8_t addr[static 16]) 00524 { 00525 memcpy(group, ADDR_MULTICAST_SOLICITED, 13); 00526 memcpy(group + 13, addr + 13, 3); 00527 } 00528 00529 static if_group_entry_t *addr_add_solicited_node_group(protocol_interface_info_entry_t *interface, const uint8_t address[static 16]) 00530 { 00531 uint8_t group[16]; 00532 addr_generate_solicited_node_group(group, address); 00533 return addr_add_group(interface, group); 00534 } 00535 00536 static void addr_remove_solicited_node_group(protocol_interface_info_entry_t *interface, const uint8_t address[static 16]) 00537 { 00538 uint8_t group[16]; 00539 addr_generate_solicited_node_group(group, address); 00540 addr_remove_group(interface, group); 00541 } 00542 00543 void addr_add_router_groups(protocol_interface_info_entry_t *interface) 00544 { 00545 /* The standard IPv6 ones, but not "Realm-Local-All-Routers" 00546 * which is ZigBee IP / Thread-specific (and not IANA registered) 00547 */ 00548 addr_add_group(interface, ADDR_IF_LOCAL_ALL_ROUTERS); 00549 addr_add_group(interface, ADDR_LINK_LOCAL_ALL_ROUTERS); 00550 00551 /* We only want to join the site address on one interface per site zone, 00552 * or we'd get multiple copies of packets. Exit if we're already a member. 00553 */ 00554 ns_list_foreach(protocol_interface_info_entry_t, i, &protocol_interface_info_list) { 00555 if (i->zone_index[IPV6_SCOPE_SITE_LOCAL] == interface->zone_index[IPV6_SCOPE_SITE_LOCAL] && 00556 addr_get_group_entry(i, ADDR_SITE_LOCAL_ALL_ROUTERS)) { 00557 return; 00558 } 00559 } 00560 addr_add_group(interface, ADDR_SITE_LOCAL_ALL_ROUTERS); 00561 } 00562 00563 bool addr_am_group_member_on_interface(const protocol_interface_info_entry_t *interface, const uint8_t group[static 16]) 00564 { 00565 return addr_am_implicit_group_member(group) || addr_get_group_entry(interface, group); 00566 } 00567 00568 /* RFC 6724 Default source address selection */ 00569 const uint8_t *addr_select_source(protocol_interface_info_entry_t *interface, const uint8_t dest[static 16], uint32_t addr_preferences) 00570 { 00571 /* Let's call existing preferred address "SA" and new candidate "SB", to 00572 * make it look like a bit like RFC 6724 00573 */ 00574 if_address_entry_t *SA = NULL; 00575 uint_fast8_t scope_D = addr_ipv6_scope(dest, interface); 00576 const addr_policy_table_entry_t *policy_D = addr_get_policy(dest); 00577 00578 if (addr_preferences == 0) { 00579 addr_preferences = addr_preferences_default; 00580 } 00581 00582 /* 00583 * As we go around the loop, if we prefer the new "SB", we set SA to SB 00584 * and continue. If we decide we prefer the existing SA, we just continue. 00585 * 00586 * Careful with these macros - they must only be used with if/else, and 00587 * inside { }, as per the coding style rules. 00588 */ 00589 #define PREFER_SA continue 00590 #define PREFER_SB SA = SB; continue 00591 00592 ns_list_foreach(if_address_entry_t, SB, &interface->ip_addresses) { 00593 /* Ignore tentative addresses */ 00594 if (SB->tentative) { 00595 continue; 00596 } 00597 00598 /* First (non-tentative) address seen becomes SA */ 00599 if (!SA) { 00600 PREFER_SB; 00601 } 00602 00603 /* Rule 1: Prefer same address */ 00604 if (memcmp(SB->address, dest, 16) == 0) { 00605 SA = SB; 00606 /* It's an exact match, no point checking any other addresses */ 00607 break; 00608 } 00609 00610 /* Rule 2: Prefer appropriate scope */ 00611 uint_fast8_t scope_SA = addr_ipv6_scope(SA->address, interface); 00612 uint_fast8_t scope_SB = addr_ipv6_scope(SB->address, interface); 00613 if (scope_SA < scope_SB) { 00614 if (scope_SA < scope_D) { 00615 PREFER_SB; 00616 } else { 00617 PREFER_SA; 00618 } 00619 } else if (scope_SB < scope_SA) { 00620 if (scope_SB < scope_D) { 00621 PREFER_SA; 00622 } else { 00623 PREFER_SB; 00624 } 00625 } 00626 00627 /* Rule 3: Avoid deprecated addresses */ 00628 if (SA->preferred_lifetime != 0 && SB->preferred_lifetime == 0) { 00629 PREFER_SA; 00630 } else if (SB->preferred_lifetime != 0 && SA->preferred_lifetime == 0) { 00631 PREFER_SB; 00632 } 00633 00634 /* (Rule 4: Prefer home addresses - Mobile IPv6 not implemented) */ 00635 /* (Rule 5: Prefer outgoing interface - candidate set already limited) */ 00636 /* (Rule 5.5: Prefer addresses in a prefix advertised by the next-hop - we don't track this information) */ 00637 00638 /* Rule 6: Prefer matching label */ 00639 const addr_policy_table_entry_t *policy_SA = addr_get_policy(SA->address); 00640 const addr_policy_table_entry_t *policy_SB = addr_get_policy(SB->address); 00641 if (policy_SA->label == policy_D->label && policy_SB->label != policy_D->label) { 00642 PREFER_SA; 00643 } else if (policy_SB->label == policy_D->label && policy_SA->label != policy_D->label) { 00644 PREFER_SB; 00645 } 00646 00647 /* Rule 7: Prefer temporary addresses (or the opposite) */ 00648 if (SA->temporary != SB->temporary) { 00649 bool prefer_public = (addr_preferences & SOCKET_IPV6_PREFER_SRC_PUBLIC); 00650 00651 if (SA->temporary != prefer_public) { 00652 PREFER_SA; 00653 } else { 00654 PREFER_SB; 00655 } 00656 } 00657 00658 /* Rule 8: Use longest matching prefix */ 00659 uint_fast8_t common_SA = addr_common_prefix_len(SA->address, SA->prefix_len, dest); 00660 uint_fast8_t common_SB = addr_common_prefix_len(SB->address, SB->prefix_len, dest); 00661 if (common_SA > common_SB) { 00662 PREFER_SA; 00663 } else if (common_SB > common_SA) { 00664 PREFER_SB; 00665 } 00666 00667 /* A tie-breaker: Prefer 6LoWPAN short address (or the opposite) */ 00668 bool short_SA = SA->prefix_len == 64 && memcmp(SA->address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0; 00669 bool short_SB = SB->prefix_len == 64 && memcmp(SB->address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0; 00670 if (short_SA != short_SB) { 00671 bool prefer_short = (addr_preferences & SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT); 00672 00673 if (short_SA == prefer_short) { 00674 PREFER_SA; 00675 } else { 00676 PREFER_SB; 00677 } 00678 } 00679 00680 /* Tie */ 00681 PREFER_SA; 00682 } 00683 00684 return SA ? SA->address : NULL; 00685 } 00686 00687 /* A variant of RFC 6724 Default source address selection, to select an address 00688 * on an interface with a specific prefix. The prefix must match, and some 00689 * source address rules don't apply, but some are handled similarly. See 00690 * comments in addr_select_source. 00691 */ 00692 const uint8_t *addr_select_with_prefix(protocol_interface_info_entry_t *cur, const uint8_t *prefix, uint8_t prefix_len, uint32_t addr_preferences) 00693 { 00694 if_address_entry_t *SA = NULL; 00695 00696 if (addr_preferences == 0) { 00697 addr_preferences = addr_preferences_default; 00698 } 00699 00700 ns_list_foreach(if_address_entry_t, SB, &cur->ip_addresses) { 00701 /* Ignore tentative addresses */ 00702 if (SB->tentative) { 00703 continue; 00704 } 00705 00706 /* Prefix must match */ 00707 if (!bitsequal(SB->address, prefix, prefix_len)) { 00708 continue; 00709 } 00710 00711 /* First (non-tentative, matching prefix) address seen becomes SA */ 00712 if (!SA) { 00713 PREFER_SB; 00714 } 00715 00716 /* (Rule 1: Prefer same address - doesn't apply here) */ 00717 /* Rule 2: Was prefer appropriate scope - for this purpose we instead prefer wider scope */ 00718 uint_fast8_t scope_SA = addr_ipv6_scope(SA->address, cur); 00719 uint_fast8_t scope_SB = addr_ipv6_scope(SB->address, cur); 00720 if (scope_SA < scope_SB) { 00721 PREFER_SB; 00722 } else if (scope_SB < scope_SA) { 00723 PREFER_SA; 00724 } 00725 00726 /* Rule 3: Avoid deprecated addresses */ 00727 if (SA->preferred_lifetime != 0 && SB->preferred_lifetime == 0) { 00728 PREFER_SA; 00729 } 00730 else if (SB->preferred_lifetime != 0 && SA->preferred_lifetime == 0) { 00731 PREFER_SB; 00732 } 00733 00734 /* (Rule 4: Prefer home addresses - Mobile IPv6 not implemented) */ 00735 /* (Rule 5: Prefer outgoing interface - candidate set already limited) */ 00736 /* (Rule 5.5: Prefer addresses in a prefix advertised by the next-hop - we don't track this information) */ 00737 00738 /* Rule 6: Prefer matching label - doesn't apply here. But instead, 00739 * let's use precedence, like rule 6 of destination selection. 00740 */ 00741 const addr_policy_table_entry_t *policy_SA = addr_get_policy(SA->address); 00742 const addr_policy_table_entry_t *policy_SB = addr_get_policy(SB->address); 00743 if (policy_SA->precedence > policy_SB->precedence) { 00744 PREFER_SA; 00745 } else if (policy_SB->precedence > policy_SA->precedence) { 00746 PREFER_SB; 00747 } 00748 00749 /* Rule 7: Prefer temporary addresses (or the opposite) */ 00750 if (SA->temporary != SB->temporary) { 00751 bool prefer_public = (addr_preferences & SOCKET_IPV6_PREFER_SRC_PUBLIC); 00752 00753 if (SA->temporary != prefer_public) { 00754 PREFER_SA; 00755 } else { 00756 PREFER_SB; 00757 } 00758 } 00759 00760 /* (Rule 8: Use longest matching prefix - doesn't apply) */ 00761 00762 /* A tie-breaker: Prefer 6LoWPAN short address (or the opposite) */ 00763 bool short_SA = SA->prefix_len == 64 && memcmp(SA->address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0; 00764 bool short_SB = SB->prefix_len == 64 && memcmp(SB->address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0; 00765 if (short_SA != short_SB) { 00766 bool prefer_short = (addr_preferences & SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT); 00767 00768 if (short_SA == prefer_short) { 00769 PREFER_SA; 00770 } else { 00771 PREFER_SB; 00772 } 00773 } 00774 00775 /* Tie */ 00776 PREFER_SA; 00777 } 00778 00779 return SA ? SA->address : NULL; 00780 } 00781 00782 #undef PREFER_SA 00783 #undef PREFER_SB 00784 00785 void addr_delete_entry(protocol_interface_info_entry_t *cur, if_address_entry_t *addr) 00786 { 00787 if (addr->group_added) { 00788 addr_remove_solicited_node_group(cur, addr->address); 00789 } 00790 ns_list_remove(&cur->ip_addresses, addr); 00791 addr_cb(cur, addr, ADDR_CALLBACK_DELETED); 00792 ns_dyn_mem_free(addr); 00793 } 00794 00795 /* ticks is in 1/10s */ 00796 void addr_fast_timer(protocol_interface_info_entry_t *cur, uint_fast16_t ticks) 00797 { 00798 /* Fast timers only run while the interface is active. */ 00799 if (!(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { 00800 return; 00801 } 00802 00803 ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { 00804 if (addr->state_timer == 0) { 00805 continue; 00806 } 00807 00808 if (addr->state_timer > ticks) { 00809 addr->state_timer -= ticks; 00810 continue; 00811 } 00812 00813 addr->state_timer = 0; 00814 /* Advance DAD state machine if tentative, else give it to the protocol state machine */ 00815 if (addr->tentative) { 00816 if (addr->count == 0) { 00817 #if 0 00818 // Initial join delay finished 00819 // We don't have full MLD support - send 1 report for now 00820 // This will become a real "join" later 00821 buffer_t *mld_buf; 00822 uint8_t sol_addr[16]; 00823 memcpy(sol_addr, ADDR_MULTICAST_SOLICITED, 13); 00824 memcpy(sol_addr + 13, addr->address + 13, 3); 00825 mld_buf = mld_build(cur, NULL, ICMPV6_TYPE_INFO_MCAST_LIST_REPORT, 0, sol_addr); 00826 protocol_push(mld_buf); 00827 #endif 00828 if (addr_add_solicited_node_group(cur, addr->address)) { 00829 addr->group_added = true; 00830 } 00831 } 00832 #ifdef HAVE_IPV6_ND 00833 if (addr->count >= cur->dup_addr_detect_transmits) { 00834 /* Finished - if we've not been nerfed already, we can transition 00835 * to non-tentative. 00836 */ 00837 addr->tentative = false; 00838 addr->count = 0; 00839 tr_info("DAD passed on IF %d: %s", cur->id, trace_ipv6(addr->address)); 00840 addr_cb(cur, addr, ADDR_CALLBACK_DAD_COMPLETE); 00841 } else { 00842 buffer_t *ns_buf = icmpv6_build_ns(cur, addr->address, NULL, false, true, NULL); 00843 protocol_push(ns_buf); 00844 addr->state_timer = (cur->ipv6_neighbour_cache.retrans_timer + 50) / 100; // ms -> ticks 00845 addr->count++; 00846 } 00847 #endif 00848 } else { 00849 addr_cb(cur, addr, ADDR_CALLBACK_TIMER); 00850 } 00851 00852 /* If a callback has shut down the interface, break now - this isn't 00853 * just a nicety; it avoids an iteration failure if shutdown disrupted 00854 * the address list (as is likely). 00855 */ 00856 if (!(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { 00857 break; 00858 } 00859 } 00860 } 00861 00862 void addr_slow_timer(protocol_interface_info_entry_t *cur, uint_fast16_t seconds) 00863 { 00864 /* Slow (lifetime) timers run whether the interface is active or not */ 00865 ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { 00866 if (addr->preferred_lifetime != 0xffffffff && addr->preferred_lifetime != 0) { 00867 if (addr->preferred_lifetime > seconds) { 00868 addr->preferred_lifetime -= seconds; 00869 } else { 00870 tr_info("Address deprecated: %s", trace_ipv6(addr->address)); 00871 addr->preferred_lifetime = 0; 00872 addr_cb(cur, addr, ADDR_CALLBACK_DEPRECATED); 00873 } 00874 } 00875 00876 if (addr->valid_lifetime != 0xffffffff) { 00877 if (addr->valid_lifetime > seconds) { 00878 addr->valid_lifetime -= seconds; 00879 } else { 00880 tr_info("Address invalidated: %s", trace_ipv6(addr->address)); 00881 addr->valid_lifetime = 0; 00882 addr_cb(cur, addr, ADDR_CALLBACK_INVALIDATED); 00883 /* Give them the chance to revalidate */ 00884 if (addr->valid_lifetime == 0) { 00885 addr_delete_entry(cur, addr); 00886 } 00887 } 00888 } 00889 } 00890 00891 #ifdef MULTICAST_FORWARDING 00892 ns_list_foreach_safe(if_group_fwd_entry_t, group, &cur->ip_groups_fwd) { 00893 if (group->lifetime != 0xffffffff) { 00894 if (group->lifetime > seconds) { 00895 group->lifetime -= seconds; 00896 } else { 00897 tr_debug("MC fwd expired: %s", trace_ipv6(group->group)); 00898 addr_multicast_fwd_delete_entry(cur, group); 00899 } 00900 } 00901 } 00902 #endif 00903 } 00904 00905 static void addr_max_entries_check(protocol_interface_info_entry_t *cur, if_address_source_t source) 00906 { 00907 // Limit only auto configuration addresses 00908 if (source != ADDR_SOURCE_SLAAC || cur->ip_addresses_max_slaac_entries == 0) { 00909 return; 00910 } 00911 00912 uint8_t count = 0; 00913 if_address_entry_t *first_slaac_entry = NULL; 00914 ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { 00915 if (e->source == ADDR_SOURCE_SLAAC) { 00916 if (!first_slaac_entry) { 00917 first_slaac_entry = e; 00918 } 00919 if (++count == 0xff) { 00920 break; 00921 } 00922 } 00923 } 00924 00925 if (count > cur->ip_addresses_max_slaac_entries) { 00926 addr_delete_entry(cur, first_slaac_entry); 00927 } 00928 } 00929 00930 void addr_max_slaac_entries_set(protocol_interface_info_entry_t *cur, uint8_t max_slaac_entries) 00931 { 00932 cur->ip_addresses_max_slaac_entries = max_slaac_entries; 00933 } 00934 00935 if_address_entry_t *addr_add(protocol_interface_info_entry_t *cur, const uint8_t address[static 16], uint_fast8_t prefix_len, if_address_source_t source, uint32_t valid_lifetime, uint32_t preferred_lifetime, bool skip_dad) 00936 { 00937 if (addr_get_entry(cur, address)) { 00938 return NULL; 00939 } 00940 00941 addr_max_entries_check(cur, source); 00942 00943 if_address_entry_t *entry = ns_dyn_mem_alloc(sizeof(if_address_entry_t)); 00944 if (!entry) { 00945 return NULL; 00946 } 00947 00948 memset(entry, 0, sizeof *entry); 00949 entry->cb = NULL; 00950 memcpy(entry->address, address, 16); 00951 entry->prefix_len = prefix_len; 00952 entry->source = source; 00953 entry->valid_lifetime = valid_lifetime; 00954 entry->preferred_lifetime = preferred_lifetime; 00955 entry->group_added = false; 00956 #ifndef HAVE_IPV6_ND 00957 skip_dad = true; 00958 #endif 00959 if (skip_dad || cur->dup_addr_detect_transmits == 0) { 00960 entry->tentative = false; 00961 if (addr_add_solicited_node_group(cur, entry->address)) { 00962 entry->group_added = true; 00963 } 00964 // XXX not right? Want to do delay + MLD join, so don't special-case? 00965 /* entry->cb isn't set yet, but global notifiers will want call */ 00966 addr_cb(cur, entry, ADDR_CALLBACK_DAD_COMPLETE); 00967 } else { 00968 entry->tentative = true; 00969 // Initial timer is for the multicast join delay 00970 entry->count = 0; 00971 entry->state_timer = randLIB_get_random_in_range(1, 10); // MAX_RTR_SOLICITATION_DELAY (1s) in ticks 00972 } 00973 00974 tr_info("%sAddress added to IF %d: %s", (entry->tentative ? "Tentative " : ""), cur->id, trace_ipv6(address)); 00975 00976 ns_list_add_to_end(&cur->ip_addresses, entry); 00977 00978 return entry; 00979 } 00980 00981 int_fast8_t addr_delete(protocol_interface_info_entry_t *cur, const uint8_t address[static 16]) 00982 { 00983 ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { 00984 if (memcmp(e->address, address, 16) == 0) { 00985 addr_delete_entry(cur, e); 00986 return 0; 00987 } 00988 } 00989 00990 return -1; 00991 } 00992 00993 void addr_delete_matching(protocol_interface_info_entry_t *cur, const uint8_t *prefix, uint8_t prefix_len, if_address_source_t source) 00994 { 00995 ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) { 00996 if ((source == ADDR_SOURCE_UNKNOWN || e->source == source) && 00997 bitsequal(e->address, prefix, prefix_len)) { 00998 addr_delete_entry(cur, e); 00999 } 01000 } 01001 01002 } 01003 01004 void addr_set_non_preferred(protocol_interface_info_entry_t *cur, if_address_source_t source) 01005 { 01006 ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) { 01007 if (e->source == source) { 01008 // Sets preferred lifetime to zero or deletes tentative addresses 01009 addr_set_preferred_lifetime(cur, e, 0); 01010 } 01011 } 01012 } 01013 01014 void addr_duplicate_detected(struct protocol_interface_info_entry *interface, const uint8_t addr[static 16]) 01015 { 01016 if_address_entry_t *entry = addr_get_entry(interface, addr); 01017 if (!entry) { 01018 return; 01019 } 01020 01021 tr_warn("DAD failed: %s", trace_ipv6(addr)); 01022 01023 interface->dad_failures++; 01024 addr_cb(interface, entry, ADDR_CALLBACK_DAD_FAILED); 01025 01026 /* Callback may have done something drastic like shut down the interface. 01027 * Don't assume entry is still valid - remove it by IP address. 01028 */ 01029 addr_delete(interface, addr); 01030 } 01031 01032 void addr_notification_register(if_address_notification_fn *fn) 01033 { 01034 ns_list_foreach(addr_notification_t, n, &addr_notifications) { 01035 if (n->fn == fn) { 01036 return; 01037 } 01038 } 01039 01040 addr_notification_t *n = ns_dyn_mem_alloc(sizeof(addr_notification_t)); 01041 if (!n) { 01042 tr_error("addr_notification_register mem"); 01043 return; 01044 } 01045 n->fn = fn; 01046 ns_list_add_to_end(&addr_notifications, n); 01047 } 01048 01049 void addr_cb(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason) 01050 { 01051 ns_list_foreach(addr_notification_t, n, &addr_notifications) { 01052 n->fn(interface, addr, reason); 01053 } 01054 if (addr->cb) { 01055 addr->cb(interface, addr, reason); 01056 } 01057 } 01058 01059 void addr_set_valid_lifetime(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, uint32_t valid_lifetime) 01060 { 01061 if (valid_lifetime != addr->valid_lifetime) { 01062 addr->valid_lifetime = valid_lifetime; 01063 addr_cb(interface, addr, ADDR_CALLBACK_REFRESHED); 01064 } 01065 } 01066 01067 void addr_set_preferred_lifetime(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, uint32_t preferred_lifetime) 01068 { 01069 if (preferred_lifetime != addr->preferred_lifetime) { 01070 addr->preferred_lifetime = preferred_lifetime; 01071 if (preferred_lifetime == 0) { 01072 // Entry is deleted if it is tentative 01073 if (addr->tentative) { 01074 addr_delete_entry(interface, addr); 01075 } else { 01076 addr_cb(interface, addr, ADDR_CALLBACK_DEPRECATED); 01077 } 01078 } 01079 } 01080 } 01081 01082 void memswap(uint8_t *restrict a, uint8_t *restrict b, uint_fast8_t len) 01083 { 01084 while (len--) { 01085 uint8_t t = *a; 01086 *a++ = *b; 01087 *b++ = t; 01088 } 01089 } 01090 01091 /* Optimised for quick discard of mismatching addresses (eg in a cache lookup): 01092 * searches BACKWARDS, as last bytes are most likely to differ. 01093 */ 01094 bool addr_ipv6_equal(const uint8_t a[static 16], const uint8_t b[static 16]) 01095 { 01096 for (int_fast8_t n = 15; n >= 0; n--) { 01097 if (a[n] != b[n]) { 01098 return false; 01099 } 01100 } 01101 return true; 01102 } 01103 01104 bool addr_iid_matches_eui64(const uint8_t iid[static 8], const uint8_t eui64[static 8]) 01105 { 01106 for (int_fast8_t n = 7; n >= 1; n--) { 01107 if (iid[n] != eui64[n]) { 01108 return false; 01109 } 01110 } 01111 return iid[0] == (eui64[0] ^ 2); 01112 } 01113 01114 bool addr_iid_matches_lowpan_short(const uint8_t iid[static 8], uint16_t short_addr) 01115 { 01116 if (iid[7] != (short_addr & 0xFF) || 01117 iid[6] != (short_addr >> 8)) { 01118 return false; 01119 } 01120 01121 for (int_fast8_t n = 5; n >= 0; n--) { 01122 if (iid[n] != ADDR_SHORT_ADR_SUFFIC[n]) { 01123 return false; 01124 } 01125 } 01126 return true; 01127 } 01128 01129 bool addr_iid_reserved(const uint8_t iid[static 8]) 01130 { 01131 static const uint8_t reserved_iana[5] = { 0x02, 0x00, 0x5e, 0xff, 0xfe }; 01132 static const uint8_t reserved_subnet_anycast[7] = { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 01133 01134 if (memcmp(iid, ADDR_UNSPECIFIED + 8, 8) == 0) { 01135 return true; // subnet-router anycast 01136 } 01137 01138 if (memcmp(iid, reserved_iana, 5) == 0) { 01139 return true; 01140 } 01141 01142 if (memcmp(iid, reserved_subnet_anycast, 7) == 0 && iid[7] >= 0x80) { 01143 return true; 01144 } 01145 01146 return false; 01147 } 01148 01149 int_fast8_t addr_opaque_iid_key_set(const void *secret_key, uint8_t key_len) 01150 { 01151 /* Delete existing info */ 01152 if (addr_iid_secret_key) { 01153 ns_dyn_mem_free((void *) addr_iid_secret_key); 01154 addr_iid_secret_key = NULL; 01155 addr_iid_secret_key_len = 0; 01156 } 01157 01158 /* If disabling, that's it */ 01159 if (secret_key == NULL) { 01160 return 0; 01161 } 01162 /* Attempt to copy new info */ 01163 uint8_t *copy = ns_dyn_mem_alloc(key_len); 01164 if (!copy) { 01165 return -1; 01166 } 01167 addr_iid_secret_key = memcpy(copy, secret_key, key_len); 01168 addr_iid_secret_key_len = key_len; 01169 return 0; 01170 } 01171 01172 int_fast8_t addr_opaque_initial_iid_set(const void *iid) 01173 { 01174 /* Delete existing info */ 01175 if (addr_initial_iid) { 01176 ns_dyn_mem_free((void *) addr_initial_iid); 01177 addr_initial_iid = NULL; 01178 } 01179 if (!iid) { 01180 return 0; 01181 } 01182 /* Attempt to copy new info */ 01183 uint8_t *copy = ns_dyn_mem_alloc(8); 01184 if (!copy) { 01185 return -1; 01186 } 01187 addr_initial_iid = memcpy(copy, iid, 8); 01188 return 0; 01189 } 01190 01191 bool addr_opaque_iid_key_is_set(void) 01192 { 01193 return addr_iid_secret_key != NULL; 01194 } 01195 01196 /* RFC 7217 generation: addr must be prepopulated with 8-byte prefix, and secret key must be set */ 01197 void addr_generate_opaque_iid(protocol_interface_info_entry_t *cur, uint8_t addr[static 16]) 01198 { 01199 opaque_retry: 01200 01201 if (addr_initial_iid && !cur->dad_failures) { 01202 // This is test implementations use only normally should not need this. 01203 memcpy(addr + 8,addr_initial_iid,8); 01204 return; 01205 } 01206 { 01207 // Limit scope to try to minimise stack, given the goto 01208 ns_sha256_context ctx; 01209 ns_sha256_init(&ctx); 01210 ns_sha256_starts(&ctx); 01211 ns_sha256_update(&ctx, addr, 8); 01212 if (cur->interface_name) { 01213 /* This isn't ideal - there's no guarantee each instance of a driver has a distinct name */ 01214 ns_sha256_update(&ctx, cur->interface_name, strlen(cur->interface_name)); 01215 } else { 01216 ns_sha256_update(&ctx, &cur->id, sizeof cur->id); 01217 } 01218 ns_sha256_update(&ctx, &cur->dad_failures, sizeof cur->dad_failures); 01219 ns_sha256_update(&ctx, addr_iid_secret_key, addr_iid_secret_key_len); 01220 ns_sha256_finish_nbits(&ctx, addr + 8, 64); 01221 ns_sha256_free(&ctx); 01222 } 01223 /* Note that we only check for reserved IIDs - as per RFC 7217, 01224 * there's no restriction on U/G bits. 01225 */ 01226 if (addr_iid_reserved(addr + 8)) { 01227 cur->dad_failures++; 01228 goto opaque_retry; 01229 } 01230 } 01231 01232 /* Write a LoWPAN IPv6 address, based on a prefix and short address */ 01233 uint8_t *addr_ipv6_write_from_lowpan_short(uint8_t dst[static 16], const uint8_t prefix[static 8], uint16_t short_addr) 01234 { 01235 common_write_16_bit(short_addr, dst + 14); 01236 memcpy(dst + 8, ADDR_SHORT_ADR_SUFFIC, 6); 01237 return memcpy(dst, prefix, 8); 01238 } 01239 01240 /* Turn an address (either MAC or IP) into a base IP address for context compression */ 01241 bool addr_iid_from_outer(uint8_t iid_out[static 8], const sockaddr_t *addr_in) 01242 { 01243 switch (addr_in->addr_type ) { 01244 case ADDR_802_15_4_LONG : 01245 memcpy(iid_out, addr_in->address + 2, 8); 01246 iid_out[0] ^= 2; 01247 break; 01248 case ADDR_BROADCAST : 01249 case ADDR_802_15_4_SHORT : 01250 memcpy(iid_out, ADDR_SHORT_ADR_SUFFIC, 6); 01251 iid_out[6] = addr_in->address [2]; 01252 iid_out[7] = addr_in->address [3]; 01253 break; 01254 case ADDR_IPV6 : 01255 memcpy(iid_out, addr_in->address + 8, 8); 01256 break; 01257 default: 01258 return false; 01259 } 01260 01261 return true; 01262 } 01263 01264 int addr_interface_set_ll64(protocol_interface_info_entry_t *cur, if_address_callback_fn *cb) 01265 { 01266 int ret_val = -1; 01267 if_address_entry_t *address_entry = NULL; 01268 uint8_t temp_ll64[16]; 01269 memcpy(temp_ll64, ADDR_LINK_LOCAL_PREFIX, 8); 01270 memcpy(temp_ll64 + 8, cur->iid_eui64, 8); 01271 01272 address_entry = addr_add(cur, temp_ll64, 64, ADDR_SOURCE_UNKNOWN, 0xffffffff, 0xffffffff, false); 01273 if (address_entry) { 01274 tr_debug("LL64 Register OK!"); 01275 ret_val = 0; 01276 address_entry->cb = cb; 01277 if (!address_entry->tentative) { 01278 addr_cb(cur, address_entry, ADDR_CALLBACK_DAD_COMPLETE); 01279 } 01280 } 01281 return ret_val; 01282 } 01283 01284 /* address_type 0 means "any" address - we return short by preference */ 01285 /* address_type 1 means long address - we ignore short addresses */ 01286 int8_t addr_interface_get_ll_address(protocol_interface_info_entry_t *cur, uint8_t *address_ptr, uint8_t address_type) 01287 { 01288 const uint8_t *short_addr = NULL; 01289 const uint8_t *long_addr = NULL; 01290 01291 if (!cur) { 01292 return -1; 01293 } 01294 01295 ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { 01296 if (!e->tentative && addr_is_ipv6_link_local(e->address)) { 01297 if (cur->nwk_id == IF_6LoWPAN && memcmp(e->address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0) { 01298 short_addr = e->address; 01299 } else { 01300 long_addr = e->address; 01301 } 01302 01303 if (long_addr && short_addr) { 01304 break; 01305 } 01306 } 01307 } 01308 01309 if (short_addr && address_type != 1) { 01310 if (address_ptr) { 01311 memcpy(address_ptr, short_addr, 16); 01312 } 01313 return 0; 01314 } else if (long_addr) { 01315 if (address_ptr) { 01316 memcpy(address_ptr, long_addr, 16); 01317 } 01318 return 0; 01319 } else { 01320 return -1; 01321 } 01322 } 01323 01324 bool addr_interface_all_address_ready(protocol_interface_info_entry_t *cur) 01325 { 01326 if (!cur) { 01327 return false; 01328 } 01329 01330 ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { 01331 if (e->tentative) { 01332 return false; 01333 } 01334 } 01335 return true; 01336 } 01337 01338 int8_t addr_interface_gp_prefix_compare(protocol_interface_info_entry_t *cur, const uint8_t *prefix) 01339 { 01340 if (cur->global_address_available) { 01341 ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { 01342 if (memcmp(e->address, prefix, 8) == 0) { 01343 return 0; 01344 } 01345 } 01346 } 01347 return -1; 01348 } 01349 01350 int8_t addr_interface_address_compare(protocol_interface_info_entry_t *cur, const uint8_t *addr) 01351 { 01352 /* First check the specified interface */ 01353 if (addr_is_assigned_to_interface(cur, addr)) { 01354 return 0; 01355 } 01356 01357 /* Then check other interfaces, enforcing scope zones */ 01358 uint_fast8_t scope = addr_ipv6_scope(addr, cur); 01359 ns_list_foreach(protocol_interface_info_entry_t, other, &protocol_interface_info_list) { 01360 if (other != cur && 01361 other->zone_index[scope] == cur->zone_index[scope] && 01362 addr_is_assigned_to_interface(other, addr)) { 01363 // special handling for Thread - external global-scope ULA coming in, 01364 // which would match, but we need to restrict if that ULA is mesh-local 01365 // on the Thread side. 01366 if (thread_info(other) && addr_ipv6_scope(addr, other) <= IPV6_SCOPE_REALM_LOCAL) { 01367 continue; 01368 } 01369 return 0; 01370 } 01371 } 01372 01373 return -1; 01374 } 01375 01376 int8_t addr_interface_select_source(protocol_interface_info_entry_t *cur, uint8_t *src_ptr, const uint8_t *dest, uint32_t addr_preferences) 01377 { 01378 int8_t ret_val = -1; 01379 if (cur) { 01380 const uint8_t *src = addr_select_source(cur, dest, addr_preferences); 01381 if (src) { 01382 memcpy(src_ptr, src, 16); 01383 ret_val = 0; 01384 } 01385 } 01386 return ret_val; 01387 } 01388 01389 // This last function must always be compiled with tracing enabled 01390 #ifndef FEA_TRACE_SUPPORT 01391 #define FEA_TRACE_SUPPORT 1 01392 #include "mbed-trace/mbed_trace.h" 01393 #endif 01394 char* trace_sockaddr(const sockaddr_t* addr, bool panid_prefix) 01395 { 01396 uint8_t length = addr_len_from_type(addr->addr_type ); 01397 01398 if (length == 0) { 01399 return "<n/a>"; 01400 } 01401 01402 /* Awkward hack for 802.15.4 address types */ 01403 if (addr->addr_type == ADDR_802_15_4_SHORT || 01404 addr->addr_type == ADDR_802_15_4_LONG ) { 01405 length -= (panid_prefix) ? 0 : 2; 01406 } 01407 01408 /* Start from index 0 (prints PAN ID if exists) */ 01409 return trace_array(&addr->address [0], length); 01410 }
Generated on Tue Jul 12 2022 12:43:27 by
