BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
address.c
Go to the documentation of this file.
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 /* If link-local, that's it */ 01358 if (addr_is_ipv6_link_local(addr)) { 01359 return -1; 01360 } 01361 01362 /* Now check other interfaces */ 01363 /* TODO: should only do this if both current and other interface have forwarding enabled */ 01364 return protcol_interface_address_compare(cur, addr); 01365 } 01366 01367 int8_t addr_interface_select_source(protocol_interface_info_entry_t *cur, uint8_t *src_ptr, const uint8_t *dest, uint32_t addr_preferences) 01368 { 01369 int8_t ret_val = -1; 01370 if (cur) { 01371 const uint8_t *src = addr_select_source(cur, dest, addr_preferences); 01372 if (src) { 01373 memcpy(src_ptr, src, 16); 01374 ret_val = 0; 01375 } 01376 } 01377 return ret_val; 01378 } 01379 01380 // This last function must always be compiled with tracing enabled 01381 #ifndef FEA_TRACE_SUPPORT 01382 #define FEA_TRACE_SUPPORT 1 01383 #include "mbed-trace/mbed_trace.h" 01384 #endif 01385 char* trace_sockaddr(const sockaddr_t* addr, bool panid_prefix) 01386 { 01387 uint8_t length = addr_len_from_type(addr->addr_type ); 01388 01389 if (length == 0) { 01390 return "<n/a>"; 01391 } 01392 01393 /* Awkward hack for 802.15.4 address types */ 01394 if (addr->addr_type == ADDR_802_15_4_SHORT || 01395 addr->addr_type == ADDR_802_15_4_LONG ) { 01396 length -= (panid_prefix) ? 0 : 2; 01397 } 01398 01399 /* Start from index 0 (prints PAN ID if exists) */ 01400 return trace_array(&addr->address [0], length); 01401 }
Generated on Tue Jul 12 2022 12:21:34 by
