Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ns_address_internal.c Source File

ns_address_internal.c

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