Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers address.c Source File

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 }