3 * Copyright (c) 2019-2020 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * This file contains the implementation for Thread Border Router routing.
18 * The state of the Thread network is tracked, the state of the infrastructure
19 * network is tracked, and policy decisions are made as to what to advertise
23 #include <sys/socket.h>
25 #include <net/route.h>
26 #include <netinet/in.h>
27 #include <netinet6/in6_var.h>
28 #include <netinet/icmp6.h>
29 #include <netinet6/nd6.h>
30 #include <net/if_media.h>
37 #include <arpa/inet.h>
38 #include <sys/sysctl.h>
44 #include <TargetConditionals.h>
45 #include <SystemConfiguration/SystemConfiguration.h>
46 #include <SystemConfiguration/SCPrivate.h>
47 #include <SystemConfiguration/SCNetworkConfigurationPrivate.h>
48 #include <SystemConfiguration/SCNetworkSignature.h>
49 #include <network_information.h>
51 #include <CoreUtils/CoreUtils.h>
52 #endif // IOLOOP_MACOS
55 // For now, we need backwards compatibility with old service type, only on the server.
56 # define THREAD_SERVICE_SEND_BOTH 1
64 #include "cti-services.h"
67 #include "srp-proxy.h"
71 struct rt_msghdr route
;
72 struct if_msghdr interface
;
73 struct if_msghdr2 if2
;
74 struct ifa_msghdr address
;
78 typedef struct icmp_listener
{
81 uint32_t unsolicited_interval
;
84 typedef struct thread_prefix thread_prefix_t
;
85 struct thread_prefix
{
87 thread_prefix_t
*next
;
88 struct in6_addr prefix
;
90 bool user
, ncp
, stable
;
91 bool previous_user
, previous_ncp
, previous_stable
;
93 struct thread_prefix
*thread_prefixes
, *published_thread_prefix
, *adopted_thread_prefix
;
95 typedef struct thread_pref_id thread_pref_id_t
;
96 struct thread_pref_id
{
98 thread_pref_id_t
*next
;
99 uint8_t partition_id
[4]; // Partition id on which this prefix is claimed
100 uint8_t prefix
[5]; // 40-bit ULA prefix identifier (no need to keep the whole prefix)
101 bool user
, ncp
, stable
;
102 bool previous_user
, previous_ncp
, previous_stable
;
104 struct thread_pref_id
*thread_pref_ids
;
106 typedef struct thread_service thread_service_t
;
107 struct thread_service
{
109 thread_service_t
*next
;
110 uint8_t address
[16]; // IPv6 address on which service is offered
111 uint8_t port
[2]; // Port (network byte order)
112 bool user
, ncp
, stable
;
113 bool previous_user
, previous_ncp
, previous_stable
;
115 struct thread_service
*thread_services
;
117 struct network_link
{
118 network_link_t
*next
;
121 uint8_t *NULLABLE signature
;
122 long signature_length
;
123 int32_t prefix_number
;
124 interface_t
*primary
; // This is the interface on which this prefix is being advertised.
127 interface_t
*interfaces
;
128 network_link_t
*network_links
; // Our list of network links
129 CFMutableArrayRef network_link_array
; // The same list as a CFArray, so that we can write it to preferences.
130 icmp_listener_t icmp_listener
;
131 bool have_thread_prefix
= false;
132 struct in6_addr my_thread_prefix
;
133 struct in6_addr srp_listener_ip_address
;
134 char thread_address_string
[INET6_ADDRSTRLEN
];
135 uint16_t srp_service_listen_port
;
136 uint8_t thread_partition_id
[4];
137 srp_proxy_listener_state_t
*srp_listener
;
138 struct in6_addr ula_prefix
;
139 int num_thread_interfaces
; // Should be zero or one.
141 bool advertise_default_route_on_thread
;
142 subproc_t
*thread_interface_enumerator_process
;
143 subproc_t
*thread_prefix_adder_process
;
144 subproc_t
*link_route_adder_process
;
145 subproc_t
*thread_rti_setter_process
;
146 subproc_t
*thread_forwarding_setter_process
;
147 subproc_t
*thread_proxy_service_adder_process
;
148 subproc_t
*tcpdump_logger_process
;
149 char *thread_interface_name
;
150 char *home_interface_name
;
151 bool thread_proxy_service_setup_done
;
152 bool interface_state_stable
= false;
153 bool have_non_thread_interface
= false;
156 cti_network_state_t current_thread_state
= kCTI_NCPState_Uninitialized
;
157 cti_network_node_type_t current_thread_role
= kCTI_NetworkNodeType_Unknown
;
158 cti_connection_t thread_role_context
;
159 cti_connection_t thread_state_context
;
160 cti_connection_t thread_service_context
;
161 cti_connection_t thread_prefix_context
;
162 cti_connection_t thread_partition_id_context
;
165 nw_path_evaluator_t path_evaluator
;
168 #define CONFIGURE_STATIC_INTERFACE_ADDRESSES 1
169 #define USE_IPCONFIGURATION_SERVICE 1
171 static void refresh_interface_list(void);
172 static void router_advertisement_send(interface_t
*NONNULL interface
);
173 static void icmp_send(uint8_t *NONNULL message
, size_t length
,
174 interface_t
*NONNULL interface
, const struct in6_addr
*NONNULL destination
);
175 static void interface_beacon_schedule(interface_t
*NONNULL interface
, unsigned when
);
176 static void interface_prefix_configure(struct in6_addr prefix
, interface_t
*NONNULL interface
);
177 static void interface_prefix_evaluate(interface_t
*interface
);
178 static void start_router_solicit(interface_t
*interface
);
180 static void routing_policy_evaluate_all_interfaces(bool assume_changed
);
182 static void routing_policy_evaluate(interface_t
*interface
, bool assume_changed
);
183 static void post_solicit_policy_evaluate(void *context
);
186 static void partition_state_reset(void);
187 static void partition_unpublish_prefix(thread_prefix_t
*NONNULL prefix
);
188 static void partition_unpublish_adopted_prefix(bool wait
);
189 static void partition_publish_my_prefix(void);
190 static void partition_adopt_prefix(thread_prefix_t
*NONNULL prefix
);
191 static bool partition_prefix_is_present(struct in6_addr
*prefix_addr
, int length
);
192 static bool partition_pref_id_is_present(struct in6_addr
*NONNULL prefix_addr
);
193 static thread_prefix_t
*NULLABLE
partition_find_lowest_valid_prefix(void);
194 static thread_pref_id_t
*NULLABLE
partition_find_lowest_valid_pref_id(void);
195 static void partition_pref_id_timeout(void *__unused NULLABLE context
);
196 static void partition_post_election_wakeup(void *__unused NULLABLE context
);
197 static void partition_post_partition_timeout(void *__unused NULLABLE context
);
198 static void partition_discontinue_srp_service(void);
199 static void partition_utun0_address_changed(const struct in6_addr
*NONNULL addr
, enum interface_address_change change
);
200 static bool partition_wait_for_prefix_settling(wakeup_callback_t NONNULL callback
, uint64_t now
);
201 static void partition_got_tunnel_name(void);
202 static void partition_prefix_set_changed(void);
203 static void partition_pref_id_set_changed(void);
204 static void partition_id_changed(void);
205 static void partition_remove_service_done(void *__unused NULLABLE context
, cti_status_t status
);
206 static void partition_stop_advertising_service(void);
207 static void partition_proxy_listener_ready(void *__unused NULLABLE context
, uint16_t port
);
208 static void partition_maybe_advertise_service(void);
209 static void partition_service_set_changed(void);
210 static void partition_maybe_enable_services(void);
211 static void partition_disable_service(void);
212 static void partition_schedule_service_add_wakeup(void);
214 static uint64_t partition_last_prefix_set_change
;
215 static uint64_t partition_last_pref_id_set_change
;
216 static uint64_t partition_last_partition_id_change
;
217 static uint64_t partition_last_role_change
;
218 static uint64_t partition_last_state_change
;
219 static uint64_t partition_settle_start
;
220 static uint64_t partition_service_last_add_time
;
221 static bool partition_id_is_known
;
222 static bool partition_have_prefix_list
;
223 static bool partition_have_pref_id_list
;
224 static bool partition_tunnel_name_is_known
;
225 static bool partition_can_advertise_service
;
226 static bool partition_service_blocked
;
227 static bool partition_can_provide_routing
;
228 static bool partition_may_offer_service
= false;
229 static bool partition_settle_satisfied
= true;
230 static wakeup_t
*partition_settle_wakeup
;
231 static wakeup_t
*partition_post_partition_wakeup
;
232 static wakeup_t
*partition_pref_id_wait_wakeup
;
233 static wakeup_t
*partition_service_add_pending_wakeup
;
237 interface_finalize(void *context
)
239 interface_t
*interface
= context
;
240 if (interface
->name
!= NULL
) {
241 free(interface
->name
);
243 if (interface
->beacon_wakeup
!= NULL
) {
244 ioloop_wakeup_release(interface
->beacon_wakeup
);
246 if (interface
->post_solicit_wakeup
!= NULL
) {
247 ioloop_wakeup_release(interface
->post_solicit_wakeup
);
249 if (interface
->router_solicit_wakeup
!= NULL
) {
250 ioloop_wakeup_release(interface
->router_solicit_wakeup
);
252 if (interface
->deconfigure_wakeup
!= NULL
) {
253 ioloop_wakeup_release(interface
->deconfigure_wakeup
);
259 interface_retain_(interface_t
*interface
, const char *file
, int line
)
261 (void)file
; (void)line
;
266 interface_release_(interface_t
*interface
, const char *file
, int line
)
268 (void)file
; (void)line
;
269 RELEASE(interface
, interface_finalize
);
273 interface_create_(const char *name
, int ifindex
, const char *file
, int line
)
278 ERROR("interface_create: missing name");
282 ret
= calloc(1, sizeof(*ret
));
285 ret
->name
= strdup(name
);
286 if (ret
->name
== NULL
) {
287 ERROR("interface_create: no memory for name");
288 RELEASE(ret
, interface_finalize
);
291 ret
->deconfigure_wakeup
= ioloop_wakeup_create();
292 if (ret
->deconfigure_wakeup
== NULL
) {
293 ERROR("No memory for interface deconfigure wakeup on " PUB_S_SRP
".", ret
->name
);
294 RELEASE(ret
, interface_finalize
);
298 ret
->index
= ifindex
;
299 ret
->inactive
= true;
300 // Interfaces are ineligible for routing until explicitly identified as eligible.
301 ret
->ineligible
= true;
308 thread_prefix_finalize(thread_prefix_t
*prefix
)
313 #define thread_prefix_create(prefix, prefix_length) thread_prefix_create_(prefix, prefix_length, __FILE__, __LINE__)
314 static thread_prefix_t
*
315 thread_prefix_create_(struct in6_addr
*address
, int prefix_length
, const char *file
, int line
)
317 thread_prefix_t
*prefix
;
319 prefix
= calloc(1, (sizeof *prefix
));
320 if (prefix
!= NULL
) {
321 memcpy(&prefix
->prefix
, address
, 16);
322 prefix
->prefix_len
= prefix_length
;
329 thread_service_finalize(thread_service_t
*service
)
334 #define thread_service_create(address, port) thread_service_create_(address, port, __FILE__, __LINE__)
335 static thread_service_t
*
336 thread_service_create_(uint8_t *address
, uint8_t *port
, const char *file
, int line
)
338 thread_service_t
*service
;
340 service
= calloc(1, sizeof(*service
));
341 if (service
!= NULL
) {
342 memcpy(&service
->address
, address
, 16);
343 memcpy(&service
->port
, port
, 2);
350 thread_pref_id_finalize(thread_pref_id_t
*pref_id
)
355 #define thread_pref_id_create(partition_id, prefix) thread_pref_id_create_(partition_id, prefix, __FILE__, __LINE__)
356 static thread_pref_id_t
*
357 thread_pref_id_create_(uint8_t *partition_id
, uint8_t *prefix
, const char *file
, int line
)
359 thread_pref_id_t
*pref_id
;
361 pref_id
= calloc(1, sizeof(*pref_id
));
362 if (pref_id
!= NULL
) {
363 memcpy(&pref_id
->partition_id
, partition_id
, 4);
364 memcpy(&pref_id
->prefix
, prefix
, 5);
372 icmp_message_free(icmp_message_t
*message
)
374 if (message
->options
!= NULL
) {
375 free(message
->options
);
381 icmp_message_dump(icmp_message_t
*message
,
382 const struct in6_addr
* const source_address
, const struct in6_addr
* const destination_address
)
384 link_layer_address_t
*lladdr
;
385 prefix_information_t
*prefix_info
;
386 route_information_t
*route_info
;
388 char retransmission_timer_buf
[11]; // Maximum size of a uint32_t printed as decimal.
389 char *retransmission_timer
= "infinite";
391 if (message
->retransmission_timer
!= ND6_INFINITE_LIFETIME
) {
392 snprintf(retransmission_timer_buf
, sizeof(retransmission_timer_buf
), "%" PRIu32
, message
->retransmission_timer
);
393 retransmission_timer
= retransmission_timer_buf
;
396 SEGMENTED_IPv6_ADDR_GEN_SRP(source_address
->s6_addr
, src_addr_buf
);
397 SEGMENTED_IPv6_ADDR_GEN_SRP(destination_address
->s6_addr
, dst_addr_buf
);
398 if (message
->type
== icmp_type_router_advertisement
) {
399 INFO("router advertisement from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
400 " hop_limit %d on " PUB_S_SRP
": checksum = %x "
401 "cur_hop_limit = %d flags = %x router_lifetime = %d reachable_time = %" PRIu32
402 " retransmission_timer = " PUB_S_SRP
,
403 SEGMENTED_IPv6_ADDR_PARAM_SRP(source_address
->s6_addr
, src_addr_buf
),
404 SEGMENTED_IPv6_ADDR_PARAM_SRP(destination_address
->s6_addr
, dst_addr_buf
),
405 message
->hop_limit
, message
->interface
->name
, message
->checksum
, message
->cur_hop_limit
, message
->flags
,
406 message
->router_lifetime
, message
->reachable_time
, retransmission_timer
);
407 } else if (message
->type
== icmp_type_router_solicitation
) {
408 INFO("router solicitation from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
409 " hop_limit %d on " PUB_S_SRP
": code = %d checksum = %x",
410 SEGMENTED_IPv6_ADDR_PARAM_SRP(source_address
->s6_addr
, src_addr_buf
),
411 SEGMENTED_IPv6_ADDR_PARAM_SRP(destination_address
->s6_addr
, dst_addr_buf
),
412 message
->hop_limit
, message
->interface
->name
,
413 message
->code
, message
->checksum
);
415 INFO("icmp message from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
" hop_limit %d on "
416 PUB_S_SRP
": type = %d code = %d checksum = %x",
417 SEGMENTED_IPv6_ADDR_PARAM_SRP(source_address
->s6_addr
, src_addr_buf
),
418 SEGMENTED_IPv6_ADDR_PARAM_SRP(destination_address
->s6_addr
, dst_addr_buf
),
419 message
->hop_limit
, message
->interface
->name
, message
->type
,
420 message
->code
, message
->checksum
);
423 for (i
= 0; i
< message
->num_options
; i
++) {
424 icmp_option_t
*option
= &message
->options
[i
];
425 switch(option
->type
) {
426 case icmp_option_source_link_layer_address
:
427 lladdr
= &option
->option
.link_layer_address
;
428 INFO(" source link layer address " PRI_MAC_ADDR_SRP
, MAC_ADDR_PARAM_SRP(lladdr
->address
));
430 case icmp_option_target_link_layer_address
:
431 lladdr
= &option
->option
.link_layer_address
;
432 INFO(" destination link layer address " PRI_MAC_ADDR_SRP
, MAC_ADDR_PARAM_SRP(lladdr
->address
));
434 case icmp_option_prefix_information
:
435 prefix_info
= &option
->option
.prefix_information
;
436 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix_info
->prefix
.s6_addr
, prefix_buf
);
437 INFO(" prefix info: " PRI_SEGMENTED_IPv6_ADDR_SRP
"/%d %x %" PRIu32
" %" PRIu32
,
438 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix_info
->prefix
.s6_addr
, prefix_buf
), prefix_info
->length
,
439 prefix_info
->flags
, prefix_info
->valid_lifetime
, prefix_info
->preferred_lifetime
);
441 case icmp_option_route_information
:
442 route_info
= &option
->option
.route_information
;
443 SEGMENTED_IPv6_ADDR_GEN_SRP(route_info
->prefix
.s6_addr
, router_prefix_buf
);
444 INFO(" route info: " PRI_SEGMENTED_IPv6_ADDR_SRP
"/%d %x %d",
445 SEGMENTED_IPv6_ADDR_PARAM_SRP(route_info
->prefix
.s6_addr
, router_prefix_buf
), route_info
->length
,
446 route_info
->flags
, route_info
->route_lifetime
);
449 INFO(" option type %d", option
->type
);
456 icmp_message_parse_options(icmp_message_t
*message
, uint8_t *icmp_buf
, unsigned length
, unsigned *offset
)
458 uint8_t option_type
, option_length_8
;
459 unsigned option_length
;
460 unsigned scan_offset
= *offset
;
461 icmp_option_t
*option
;
463 prefix_information_t
*prefix_information
;
464 route_information_t
*route_information
;
467 // Count the options and validate the lengths
468 while (scan_offset
< length
) {
469 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &option_type
)) {
472 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &option_length_8
)) {
475 if (scan_offset
+ option_length_8
* 8 - 2 > length
) {
476 ERROR("icmp_option_parse: option type %d length %d is longer than remaining available space %u",
477 option_type
, option_length_8
* 8, length
- scan_offset
+ 2);
480 scan_offset
+= option_length_8
* 8 - 2;
481 message
->num_options
++;
483 message
->options
= calloc(message
->num_options
, sizeof(*message
->options
));
484 if (message
->options
== NULL
) {
485 ERROR("No memory for icmp options.");
488 option
= message
->options
;
489 while (*offset
< length
) {
490 scan_offset
= *offset
;
491 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &option_type
)) {
494 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &option_length_8
)) {
497 // We already validated the length in the previous pass.
498 option
->type
= option_type
;
499 option_length
= option_length_8
* 8;
501 switch(option_type
) {
502 case icmp_option_source_link_layer_address
:
503 case icmp_option_target_link_layer_address
:
504 // At this juncture we are assuming that everything we care about looks like an
505 // ethernet interface. So for this case, length should be 8.
506 if (option_length
!= 8) {
507 INFO("Ignoring unexpectedly long link layer address: %d", option_length
);
508 // Don't store the option.
509 message
->num_options
--;
510 *offset
+= option_length
;
513 option
->option
.link_layer_address
.length
= 6;
514 memcpy(option
->option
.link_layer_address
.address
, &icmp_buf
[scan_offset
], 6);
516 case icmp_option_prefix_information
:
517 prefix_information
= &option
->option
.prefix_information
;
518 // Only a length of 32 is valid. This is an invalid ICMP packet, not just misunderunderstood
519 if (option_length
!= 32) {
523 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &prefix_information
->length
)) {
527 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &prefix_information
->flags
)) {
531 if (!dns_u32_parse(icmp_buf
, length
, &scan_offset
,
532 &prefix_information
->valid_lifetime
)) {
535 // preferred lifetime 32
536 if (!dns_u32_parse(icmp_buf
, length
, &scan_offset
,
537 &prefix_information
->preferred_lifetime
)) {
541 if (!dns_u32_parse(icmp_buf
, length
, &scan_offset
, &reserved32
)) {
545 memcpy(&prefix_information
->prefix
, &icmp_buf
[scan_offset
], 16);
547 case icmp_option_route_information
:
548 route_information
= &option
->option
.route_information
;
551 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &route_information
->length
)) {
554 switch(option_length
) {
565 ERROR("invalid route information option length %d for route length %d",
566 option_length
, route_information
->length
);
570 if (!dns_u8_parse(icmp_buf
, length
, &scan_offset
, &route_information
->flags
)) {
574 if (!dns_u32_parse(icmp_buf
, length
, &scan_offset
, &route_information
->route_lifetime
)) {
577 // route (64, 96 or 128)
578 if (prefix_bytes
> 0) {
579 memcpy(&route_information
->prefix
, &icmp_buf
[scan_offset
], prefix_bytes
);
581 memset(&((uint8_t *)&route_information
->prefix
)[prefix_bytes
], 0, 16 - prefix_bytes
);
584 case icmp_option_mtu
:
585 case icmp_option_redirected_header
:
589 *offset
+= option_length
;
596 set_router_mode(interface_t
*interface
, int mode
)
598 struct in6_ifreq router_interface
;
601 sock
= socket(PF_INET6
, SOCK_DGRAM
, 0);
603 ERROR("socket(PF_INET6, SOCK_DGRAM, 0) failed " PUB_S_SRP
": " PUB_S_SRP
, interface
->name
, strerror(errno
));
607 memset(&router_interface
, 0, sizeof (router_interface
));
608 strlcpy(router_interface
.ifr_name
, interface
->name
, sizeof(interface
->name
));
609 router_interface
.ifr_ifru
.ifru_intval
= mode
;
611 #ifndef SIOCSETROUTERMODE_IN6
612 #define SIOCSETROUTERMODE_IN6 _IOWR('i', 136, struct in6_ifreq)
613 #endif /* SIOCSETROUTERMODE_IN6 */
614 ret
= ioctl(sock
, SIOCSETROUTERMODE_IN6
, &router_interface
);
616 ERROR("Unable to enable router mode on " PUB_S_SRP
": " PUB_S_SRP
, interface
->name
, strerror(errno
));
618 INFO("enabled router mode for " PUB_S_SRP
": " PUB_S_SRP
".", interface
->name
,
619 (mode
== IPV6_ROUTER_MODE_DISABLED
621 : (mode
== IPV6_ROUTER_MODE_EXCLUSIVE
? "exclusive" : "hybrid")));
628 interface_wakeup_finalize(void *context
)
630 interface_t
*interface
= context
;
631 interface
->beacon_wakeup
= NULL
;
635 interface_deconfigure_finalize(void *context
)
637 interface_t
*interface
= context
;
638 interface
->deconfigure_wakeup
= NULL
;
642 interface_prefix_deconfigure(void *context
)
644 interface_t
*interface
= context
;
645 INFO("interface_prefix_deconfigure - ifname: " PUB_S_SRP
", prefix: "
646 ", preferred time: %" PRIu32
", valid time: %" PRIu32
, interface
->name
, interface
->preferred_lifetime
,
647 interface
->valid_lifetime
);
649 // If our on-link prefix is still deprecated (preferred_lifetime == 0 means that the prefix is in deprecated state),
650 // deconfigure it from the interface.
651 if (interface
->preferred_lifetime
== 0 && interface
->ip_configuration_service
!= NULL
) {
652 CFRelease(interface
->ip_configuration_service
);
653 interface
->ip_configuration_service
= NULL
;
654 interface
->valid_lifetime
= 0;
655 interface
->on_link_prefix_configured
= false;
656 interface
->advertise_ipv6_prefix
= false;
657 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
658 INFO("interface_prefix_deconfigure: deconfigure the prefix immediately - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
659 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
661 interface
->deprecate_deadline
= 0;
665 interface_beacon(void *context
)
667 interface_t
*interface
= context
;
668 uint64_t now
= ioloop_timenow();
670 INFO("interface_beacon:" PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP
,
671 interface
->deprecate_deadline
> now
? " ddl>now" : "",
675 partition_can_provide_routing
? " canpr" : " !canpr",
677 interface
->advertise_ipv6_prefix
? " pio" : " !pio",
678 interface
->sent_first_beacon
? "" : " first beacon");
680 if (interface
->deprecate_deadline
> now
) {
681 // The remaining valid lifetime is the time left until the deadline.
682 interface
->valid_lifetime
= (uint32_t)((interface
->deprecate_deadline
- now
) / 1000);
683 if (interface
->valid_lifetime
< icmp_listener
.unsolicited_interval
) {
684 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
685 INFO("interface_beacon: prefix valid life time is less than the unsolicited interval, stop advertising it "
686 "and prepare to deconfigure the prefix - ifname: " PUB_S_SRP
"prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
687 ", preferred time: %" PRIu32
", valid time: %" PRIu32
", unsolicited interval: %" PRIu32
,
688 interface
->name
, SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
),
689 interface
->preferred_lifetime
, interface
->valid_lifetime
, icmp_listener
.unsolicited_interval
);
690 interface
->advertise_ipv6_prefix
= false;
691 ioloop_add_wake_event(interface
->deconfigure_wakeup
,
692 interface
, interface_prefix_deconfigure
,
693 interface_deconfigure_finalize
, interface
->valid_lifetime
* 1000);
698 // If we have been beaconing, and router mode has been disabled, and we don't have
699 // an on-link prefix to advertise, discontinue beaconing.
700 if (partition_can_provide_routing
|| interface
->advertise_ipv6_prefix
) {
704 router_advertisement_send(interface
);
705 interface
->sent_first_beacon
= true;
706 interface
->last_beacon
= ioloop_timenow();;
710 if (interface
->num_beacons_sent
< 3) {
711 // Schedule a beacon for between 8 and 16 seconds in the future (<MAX_INITIAL_RTR_ADVERT_INTERVAL)
712 interface_beacon_schedule(interface
, 8000 + srp_random16() % 8000);
714 interface_beacon_schedule(interface
, icmp_listener
.unsolicited_interval
);
716 interface
->num_beacons_sent
++;
720 interface_beacon_schedule(interface_t
*interface
, unsigned when
)
722 uint64_t now
= ioloop_timenow();
725 // If we haven't sent our first beacon, now's a good time to configure router mode on the interface.
726 if (!interface
->sent_first_beacon
) {
730 mode
= (strcmp(interface
->name
, thread_interface_name
) == 0) ? IPV6_ROUTER_MODE_EXCLUSIVE
731 : IPV6_ROUTER_MODE_HYBRID
;
733 mode
= IPV6_ROUTER_MODE_HYBRID
;
735 set_router_mode(interface
, mode
);
738 // Make sure we haven't send an RA too recently.
739 if (when
< MIN_DELAY_BETWEEN_RAS
&& now
- interface
->last_beacon
< MIN_DELAY_BETWEEN_RAS
) {
740 when
= MIN_DELAY_BETWEEN_RAS
;
742 // Add up to a second of jitter.
743 when
+= srp_random16() % 1024;
744 interface
->next_beacon
= now
+ when
;
745 if (interface
->beacon_wakeup
== NULL
) {
746 interface
->beacon_wakeup
= ioloop_wakeup_create();
747 if (interface
->beacon_wakeup
== NULL
) {
748 ERROR("Unable to allocate beacon wakeup for " PUB_S_SRP
, interface
->name
);
752 // We can reschedule a beacon for sooner if we get a router solicit; in this case, we
753 // need to cancel the existing beacon wakeup, and if there is none scheduled, this will
755 ioloop_cancel_wake_event(interface
->beacon_wakeup
);
757 if (interface
->next_beacon
- now
> UINT_MAX
) {
760 interval
= (unsigned)(interface
->next_beacon
- now
);
762 INFO("Scheduling " PUB_S_SRP
"beacon on " PUB_S_SRP
" for %u milliseconds in the future",
763 interface
->sent_first_beacon
? "first " : "", interface
->name
, interval
);
764 ioloop_add_wake_event(interface
->beacon_wakeup
, interface
, interface_beacon
, interface_wakeup_finalize
, interval
);
768 router_discovery_start(interface_t
*interface
)
770 INFO("Starting router discovery on " PUB_S_SRP
, interface
->name
);
772 // Immediately when an interface shows up, start doing router solicits.
773 start_router_solicit(interface
);
775 if (interface
->post_solicit_wakeup
== NULL
) {
776 interface
->post_solicit_wakeup
= ioloop_wakeup_create();
777 if (interface
->post_solicit_wakeup
== NULL
) {
778 ERROR("No memory for post-solicit RA wakeup on " PUB_S_SRP
".", interface
->name
);
781 ioloop_cancel_wake_event(interface
->post_solicit_wakeup
);
784 // In 20 seconds, check the results of router discovery and update policy as needed.
785 if (interface
->post_solicit_wakeup
) {
786 ioloop_add_wake_event(interface
->post_solicit_wakeup
, interface
, post_solicit_policy_evaluate
,
789 interface
->router_discovery_in_progress
= true;
793 flush_stale_routers(interface_t
*interface
, uint64_t now
)
795 icmp_message_t
*router
, **p_router
;
797 // Flush stale routers.
798 for (p_router
= &interface
->routers
; *p_router
!= NULL
; ) {
800 if (now
- router
->received_time
> MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE
) {
801 *p_router
= router
->next
;
802 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, __router_src_addr_buf
);
803 INFO("flush_stale_routers: flushing stale router - ifname: " PUB_S_SRP
804 ", router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
, interface
->name
,
805 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_addr_buf
));
806 icmp_message_free(router
);
808 p_router
= &(*p_router
)->next
;
814 router_discovery_stop(interface_t
*interface
, uint64_t now
)
816 if (!interface
->router_discovery_complete
) {
817 INFO("router_discovery_stop: stopping router discovery on " PUB_S_SRP
, interface
->name
);
819 if (interface
->router_solicit_wakeup
!= NULL
) {
820 ioloop_cancel_wake_event(interface
->router_solicit_wakeup
);
822 if (interface
->post_solicit_wakeup
!= NULL
) {
823 ioloop_cancel_wake_event(interface
->post_solicit_wakeup
);
825 if (interface
->vicarious_discovery_complete
!= NULL
) {
826 ioloop_cancel_wake_event(interface
->vicarious_discovery_complete
);
827 INFO("router_discovery_stop: stopping vicarious router discovery on " PUB_S_SRP
, interface
->name
);
829 interface
->router_discovery_complete
= true;
830 interface
->router_discovery_in_progress
= false;
831 interface
->vicarious_router_discovery_in_progress
= false;
832 // clear out need_reconfigure_prefix when router_discovery_complete is set back to true.
833 interface
->need_reconfigure_prefix
= false;
834 flush_stale_routers(interface
, now
);
836 // See if we need a new prefix on the interface.
837 interface_prefix_evaluate(interface
);
841 adjust_router_received_time(interface_t
*const interface
, const uint64_t now
, const int64_t time_adjusted
)
843 icmp_message_t
*router
;
845 if (interface
->routers
== NULL
) {
846 if (interface
->advertise_ipv6_prefix
) {
847 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __ipv6_prefix
);
848 INFO("adjust_router_received_time: No router information available for the interface - "
849 "ifname: " PUB_S_SRP
", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
850 interface
->name
, SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __ipv6_prefix
));
852 INFO("adjust_router_received_time: No router information available for the interface - "
853 "ifname: " PUB_S_SRP
, interface
->name
);
859 for (router
= interface
->routers
; router
!= NULL
; router
= router
->next
) {
860 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, __router_src_addr_buf
);
861 // Only adjust the received time once.
862 if (router
->received_time_already_adjusted
) {
863 INFO("adjust_router_received_time: received time already adjusted - remaining time: %llu, "
864 "router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
, (now
- router
->received_time
) / MSEC_PER_SEC
,
865 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_addr_buf
));
868 require_action_quiet(
869 (time_adjusted
> 0 && (UINT64_MAX
- now
) > (uint64_t)time_adjusted
) ||
870 (time_adjusted
< 0 && now
> ((uint64_t)-time_adjusted
)), exit
,
871 ERROR("adjust_router_received_time: invalid adjusted values is causing overflow - "
872 "now: %" PRIu64
", time_adjusted: %" PRId64
, now
, time_adjusted
));
873 router
->received_time
= now
+ time_adjusted
;
874 router
->received_time_already_adjusted
= true; // Only adjust the icmp message received time once.
875 INFO("adjust_router_received_time: router received time is adjusted - router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
876 ", adjusted value: %" PRId64
,
877 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_addr_buf
), time_adjusted
);
885 make_all_routers_nearly_stale(interface_t
*interface
, uint64_t now
)
887 // Make every router go stale in 19.999 seconds. This means that if we don't get a response
888 // to our solicit in 20 seconds, then when the timeout callback is called, there will be no
889 // routers on the interface that aren't stale, which will trigger router discovery.
890 adjust_router_received_time(interface
, now
, 19999 - 600 * MSEC_PER_SEC
);
894 vicarious_discovery_callback(void *context
)
896 interface_t
*interface
= context
;
897 INFO("Vicarious router discovery finished on " PUB_S_SRP
".", interface
->name
);
898 interface
->vicarious_router_discovery_in_progress
= false;
899 // At this point, policy evaluate will show all the routes that were present before vicarious
900 // discovery as stale, so policy_evaluate will start router discovery if we didn't get any
901 // RAs containing on-link prefixes.
902 routing_policy_evaluate(interface
, false);
907 routing_policy_evaluate_all_interfaces(bool assume_changed
)
909 interface_t
*interface
;
911 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
912 routing_policy_evaluate(interface
, assume_changed
);
918 routing_policy_evaluate(interface_t
*interface
, bool assume_changed
)
920 icmp_message_t
*router
;
921 bool new_prefix
= false; // new prefix means that srp-mdns-proxy received a new prefix from the wire, which it
922 // did not know before.
923 bool on_link_prefix_present
= false;
924 bool something_changed
= assume_changed
;
925 uint64_t now
= ioloop_timenow();
926 bool stale_routers_exist
= false;
928 // No action on interfaces that aren't eligible for routing or that isn't currently active.
929 if (interface
->ineligible
|| interface
->inactive
) {
930 INFO("not evaluating policy on " PUB_S_SRP
" because it's " PUB_S_SRP
, interface
->name
,
931 interface
->ineligible
? "ineligible" : "inactive");
935 // See if we have a prefix from some other router
936 for (router
= interface
->routers
; router
; router
= router
->next
) {
937 icmp_option_t
*option
= router
->options
;
939 if (now
- router
->received_time
> MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE
) {
940 stale_routers_exist
= true;
941 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, router_src_addr_buf
);
942 INFO("Router " PRI_SEGMENTED_IPv6_ADDR_SRP
" is stale by %" PRIu64
" milliseconds",
943 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, router_src_addr_buf
),
944 now
- router
->received_time
);
946 for (i
= 0; i
< router
->num_options
; i
++) {
947 if (option
->type
== icmp_option_prefix_information
) {
948 prefix_information_t
*prefix
= &option
->option
.prefix_information
;
949 if ((prefix
->flags
& ND_OPT_PI_FLAG_ONLINK
) &&
950 ((prefix
->flags
& ND_OPT_PI_FLAG_AUTO
) || (router
->flags
& ND_RA_FLAG_MANAGED
)) &&
951 prefix
->preferred_lifetime
> 0)
953 // If this is a new icmp_message received now and contains PIO.
954 if (router
->new_router
) {
956 router
->new_router
= false; // clear the bit since srp-mdns-proxy already processed it.
959 // Right now all we need is to see if there is an on-link prefix.
960 on_link_prefix_present
= true;
961 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, __router_src_add_buf
);
962 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, __pio_prefix_buf
);
963 DEBUG("routing_policy_evaluate: router has PIO - ifname: " PUB_S_SRP
", router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
964 ", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
966 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_add_buf
),
967 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, __pio_prefix_buf
));
975 INFO("policy on " PUB_S_SRP
": " PUB_S_SRP
"stale " /* stale_routers_exist ? */
976 PUB_S_SRP
"disco " /* interface->router_discovery_complete ? */
977 PUB_S_SRP
"present " /* on_link_prefix_present ? */
978 PUB_S_SRP
"advert " /* interface->advertise_ipv6_prefix ? */
979 PUB_S_SRP
"conf " /* interface->on_link_prefix_configured ? */
980 PUB_S_SRP
"new_prefix " /* new_prefix ? */
981 "preferred = %" PRIu32
" valid = %" PRIu32
" deadline = %llu",
982 interface
->name
, stale_routers_exist
? "" : "!", interface
->router_discovery_complete
? "" : "!",
983 on_link_prefix_present
? "" : "!", interface
->advertise_ipv6_prefix
? "" : "!",
984 interface
->on_link_prefix_configured
? "" : "!", new_prefix
? "" : "!",
985 interface
->preferred_lifetime
, interface
->valid_lifetime
, interface
->deprecate_deadline
);
987 // If there are stale routers, start doing router discovery again to see if we can get them to respond.
988 // Also, if we have not yet done router discovery, do it now.
989 if ((!interface
->router_discovery_complete
|| stale_routers_exist
) && !on_link_prefix_present
) {
990 if (!interface
->router_discovery_in_progress
) {
991 // Start router discovery.
992 router_discovery_start(interface
);
994 INFO("routing_policy_evaluate: router discovery in progress");
997 // If we are advertising a prefix and there's another on-link prefix, deprecate the one we are
999 else if (interface
->advertise_ipv6_prefix
&& on_link_prefix_present
) {
1000 // If we have been advertising a preferred prefix, deprecate it.
1001 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
1002 if (interface
->preferred_lifetime
!= 0) {
1003 INFO("routing_policy_evaluate: deprecating interface prefix in 30 minutes - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
1004 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
1005 interface
->preferred_lifetime
= 0;
1006 interface
->deprecate_deadline
= now
+ 1800 * 1000;
1007 something_changed
= true;
1009 INFO("routing_policy_evaluate: prefix deprecating in progress - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
1010 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
1013 // If there is no on-link prefix and we aren't advertising, or have deprecated, start advertising
1014 // again (or for the first time).
1015 else if (!on_link_prefix_present
&& interface
->router_discovery_complete
&&
1016 interface
->link
!= NULL
&& interface
->link
->primary
== interface
&&
1017 (!interface
->advertise_ipv6_prefix
|| interface
->deprecate_deadline
!= 0 ||
1018 interface
->preferred_lifetime
== 0)) {
1020 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
1021 INFO("routing_policy_evaluate: advertising prefix again - ifname: " PUB_S_SRP
1022 ", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
, interface
->name
,
1023 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
1025 // If we were deprecating, stop.
1026 ioloop_cancel_wake_event(interface
->deconfigure_wakeup
);
1027 interface
->deprecate_deadline
= 0;
1029 // Start advertising immediately, 30 minutes.
1030 interface
->preferred_lifetime
= interface
->valid_lifetime
= 1800;
1032 // If the on-link prefix isn't configured on the interface, do that.
1033 if (!interface
->on_link_prefix_configured
) {
1035 if (!interface
->is_thread
) {
1037 interface_prefix_configure(interface
->ipv6_prefix
, interface
);
1040 INFO("Not setting up " PUB_S_SRP
" because it is the thread interface", interface
->name
);
1044 // Configuring the on-link prefix takes a while, so we want to re-evaluate after it's finished.
1045 interface
->advertise_ipv6_prefix
= true;
1046 something_changed
= true;
1049 // If there is no on-link prefix present, and srp-mdns-proxy itself is advertising the prefix, and it has configured
1050 // an on-link prefix, and the interface is not thread interface, and it just got an interface address removal event,
1051 // it is possible that the IPv6 routing has been flushed due to loss of address in configd, so here we explicitly
1052 // reconfigure the IPv6 prefix and the routing.
1053 else if (interface
->need_reconfigure_prefix
&& !on_link_prefix_present
&& interface
->advertise_ipv6_prefix
&&
1054 interface
->on_link_prefix_configured
&& !interface
->is_thread
) {
1055 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
1056 INFO("routing_policy_evaluate: reconfigure ipv6 prefix due to possible network changes -"
1057 " prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
1058 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
1059 interface_prefix_configure(interface
->ipv6_prefix
, interface
);
1060 interface
->need_reconfigure_prefix
= false;
1063 // If we've been looking to see if there's an on-link prefix, and we got one from the new router advertisement,
1064 // stop looking for new one.
1066 router_discovery_stop(interface
, now
);
1069 // If anything changed, do an immediate beacon; otherwise wait until the next one.
1070 // Also when something changed, set the number of transmissions back to zero so that
1071 // we send a few initial beacons quickly for reliability.
1072 if (something_changed
) {
1073 INFO("change on " PUB_S_SRP
": " PUB_S_SRP
"disco " PUB_S_SRP
"present " PUB_S_SRP
"advert " PUB_S_SRP
1074 "conf preferred = %" PRIu32
" valid = %" PRIu32
" deadline = %llu",
1075 interface
->name
, interface
->router_discovery_complete
? "" : "!", on_link_prefix_present
? "" : "!",
1076 interface
->advertise_ipv6_prefix
? "" : "!", interface
->on_link_prefix_configured
? "" : "!",
1077 interface
->preferred_lifetime
,
1078 interface
->valid_lifetime
, interface
->deprecate_deadline
);
1079 interface
->num_beacons_sent
= 0;
1080 interface_beacon_schedule(interface
, 0);
1085 start_vicarious_router_discovery_if_appropriate(interface_t
*const interface
)
1087 if (!interface
->advertise_ipv6_prefix
&&
1088 !interface
->vicarious_router_discovery_in_progress
&& !interface
->router_discovery_in_progress
)
1090 if (interface
->vicarious_discovery_complete
== NULL
) {
1091 interface
->vicarious_discovery_complete
= ioloop_wakeup_create();
1093 ioloop_cancel_wake_event(interface
->vicarious_discovery_complete
);
1095 if (interface
->vicarious_discovery_complete
!= NULL
) {
1096 ioloop_add_wake_event(interface
->vicarious_discovery_complete
,
1097 interface
, vicarious_discovery_callback
, NULL
, 20 * 1000);
1098 interface
->vicarious_router_discovery_in_progress
= true;
1100 // In order for vicarious router discovery to be useful, we need all of the routers
1101 // that were present when the first solicit was received to be stale when we give up
1102 // on vicarious discovery. If we got any router advertisements, these will not be
1103 // stale, and that means vicarious discovery succeeded.
1104 make_all_routers_nearly_stale(interface
, ioloop_timenow());
1105 INFO("start_vicarious_router_discovery_if_appropriate: Starting vicarious router discovery on " PUB_S_SRP
,
1111 router_solicit(icmp_message_t
*message
)
1113 interface_t
*iface
, *interface
;
1115 // Further validate the message
1116 if (message
->hop_limit
!= 255 || message
->code
!= 0) {
1117 ERROR("Invalid router solicitation, hop limit = %d, code = %d", message
->hop_limit
, message
->code
);
1119 if (IN6_IS_ADDR_UNSPECIFIED(&message
->source
)) {
1120 icmp_option_t
*option
= message
->options
;
1122 for (i
= 0; i
< message
->num_options
; i
++) {
1123 if (option
->type
== icmp_option_source_link_layer_address
) {
1124 ERROR("source link layer address in router solicitation from unspecified IP address");
1130 // Make sure it's not from this host
1131 for (iface
= interfaces
; iface
; iface
= iface
->next
) {
1132 if (iface
->have_link_layer_address
&& !memcmp(&message
->source
,
1133 &iface
->link_local
, sizeof(message
->source
))) {
1134 INFO("dropping router solicitation sent from this host.");
1139 interface
= message
->interface
;
1141 // Schedule an immediate send, which will be delayed by up to a second.
1142 if (!interface
->ineligible
&& !interface
->inactive
) {
1143 interface_beacon_schedule(interface
, 0);
1146 // When we receive a router solicit, it means that a host is looking for a router. We should
1147 // expect to hear replies if they are multicast. If we hear no replies, it could mean there is
1148 // no on-link prefix. In this case, we restart our own router discovery process. There is no
1149 // need to do this if we are the one advertising a prefix.
1150 start_vicarious_router_discovery_if_appropriate(interface
);
1154 router_advertisement(icmp_message_t
*message
)
1157 icmp_message_t
*router
, **rp
;
1158 if (message
->hop_limit
!= 255 || message
->code
!= 0 || !IN6_IS_ADDR_LINKLOCAL(&message
->source
)) {
1159 ERROR("Invalid router advertisement, hop limit = %d, code = %d", message
->hop_limit
, message
->code
);
1160 icmp_message_free(message
);
1163 for (iface
= interfaces
; iface
!= NULL
; iface
= iface
->next
) {
1164 if (iface
->have_link_layer_address
&& !memcmp(&message
->source
,
1165 &iface
->link_local
, sizeof(message
->source
))) {
1166 INFO("dropping router advertisement sent from this host.");
1167 icmp_message_free(message
);
1172 // See if we've had other advertisements from this router.
1173 for (rp
= &message
->interface
->routers
; *rp
!= NULL
; rp
= &(*rp
)->next
) {
1175 if (!memcmp(&router
->source
, &message
->source
, sizeof(message
->source
))) {
1176 message
->next
= router
->next
;
1178 icmp_message_free(router
);
1187 // Something may have changed, so do a policy recalculation for this interface
1188 routing_policy_evaluate(message
->interface
, false);
1192 icmp_callback(io_t
*NONNULL io
, void *__unused context
)
1195 uint8_t icmp_buf
[1500];
1196 unsigned offset
= 0, length
= 0;
1197 uint32_t reserved32
;
1200 interface_t
*interface
;
1203 rv
= ioloop_recvmsg(io
->fd
, &icmp_buf
[0], sizeof(icmp_buf
), &ifindex
, &hop_limit
, &src
, &dest
);
1205 ERROR("icmp_callback: can't read ICMP message: " PUB_S_SRP
, strerror(errno
));
1209 icmp_message_t
*message
= calloc(1, sizeof(*message
));
1210 if (message
== NULL
) {
1211 ERROR("Unable to allocate icmp_message_t for parsing");
1215 message
->source
= src
.sin6
.sin6_addr
;
1216 message
->destination
= dest
.sin6
.sin6_addr
;
1217 message
->hop_limit
= hop_limit
;
1218 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1219 if (interface
->index
== ifindex
) {
1220 message
->interface
= interface
;
1224 message
->received_time
= ioloop_timenow();
1225 message
->received_time_already_adjusted
= false;
1226 message
->new_router
= true;
1228 if (message
->interface
== NULL
) {
1229 SEGMENTED_IPv6_ADDR_GEN_SRP(message
->source
.s6_addr
, src_buf
);
1230 SEGMENTED_IPv6_ADDR_GEN_SRP(message
->destination
.s6_addr
, dst_buf
);
1231 INFO("ICMP message type %d from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
1232 " on interface index %d, which isn't listed.",
1233 icmp_buf
[0], SEGMENTED_IPv6_ADDR_PARAM_SRP(message
->source
.s6_addr
, src_buf
),
1234 SEGMENTED_IPv6_ADDR_PARAM_SRP(message
->destination
.s6_addr
, dst_buf
), ifindex
);
1235 icmp_message_free(message
);
1239 length
= (unsigned)rv
;
1240 if (length
< sizeof (struct icmp6_hdr
)) {
1241 ERROR("Short ICMP message: length %zd is shorter than ICMP header length %zd", rv
, sizeof(struct icmp6_hdr
));
1242 icmp_message_free(message
);
1246 // The increasingly innaccurately named dns parse functions will work fine for this.
1247 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->type
)) {
1250 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->code
)) {
1253 // XXX check the checksum
1254 if (!dns_u16_parse(icmp_buf
, length
, &offset
, &message
->checksum
)) {
1257 switch(message
->type
) {
1258 case icmp_type_router_advertisement
:
1259 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->cur_hop_limit
)) {
1262 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->flags
)) {
1265 if (!dns_u16_parse(icmp_buf
, length
, &offset
, &message
->router_lifetime
)) {
1268 if (!dns_u32_parse(icmp_buf
, length
, &offset
, &message
->reachable_time
)) {
1271 if (!dns_u32_parse(icmp_buf
, length
, &offset
, &message
->retransmission_timer
)) {
1275 if (!icmp_message_parse_options(message
, icmp_buf
, length
, &offset
)) {
1278 icmp_message_dump(message
, &message
->source
, &message
->destination
);
1279 router_advertisement(message
);
1280 // router_advertisement() is ressponsible for freeing the messaage if it doesn't need it.
1284 case icmp_type_router_solicitation
:
1285 if (!dns_u32_parse(icmp_buf
, length
, &offset
, &reserved32
)) {
1288 if (!icmp_message_parse_options(message
, icmp_buf
, length
, &offset
)) {
1291 icmp_message_dump(message
, &message
->source
, &message
->destination
);
1292 router_solicit(message
);
1294 case icmp_type_neighbor_advertisement
:
1295 case icmp_type_neighbor_solicitation
:
1296 case icmp_type_echo_request
:
1297 case icmp_type_echo_reply
:
1298 case icmp_type_redirect
:
1303 icmp_message_free(message
);
1307 #ifdef MONITOR_ROUTING_SOCKET
1309 route_message(io_t
*__unused rt
, route_message_t
*message
)
1313 switch(message
->route
.rtm_type
) {
1314 // When an interface goes up, or when an address is added, we get one of these.
1316 INFO("Message length %d, version %d, type RTM_NEWADDR, index %d",
1317 message
->len
, message
->route
.rtm_version
, message
->address
.ifam_index
);
1318 // ifa_msghdr followed by zero or more addresses
1319 // Addresses start on 32-bit boundaries and are sockaddrs with sa_len indicating the size.
1320 addr
= (addr_t
*)((&message
->address
) + 1);
1322 // When an interface goes down, we may get one of these. Also when an address is deleted for some reason.
1324 INFO("Message length %d, version %d, type RTM_DELADDR, index %d",
1325 message
->len
, message
->route
.rtm_version
, message
->address
.ifam_index
);
1326 // ifa_msghdr followed by zero or more addresses
1327 addr
= (addr_t
*)((&message
->address
) + 1);
1329 // When an interface goes up or down, we get one of these.
1331 INFO("Message length %d, version %d, type RTM_IFINFO, index %d",
1332 message
->len
, message
->route
.rtm_version
, message
->interface
.ifm_index
);
1333 // if_msghdr followed by zero or more addresses
1334 addr
= (addr_t
*)((&message
->interface
) + 1);
1337 INFO("Message length %d, version %d, type RTM_IFINFO2, index %d",
1338 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1339 addr
= (addr_t
*)((&message
->if2
) + 1);
1342 INFO("Message length %d, version %d, type RTM_ADD, index %d",
1343 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1344 addr
= (addr_t
*)((&message
->if2
) + 1);
1347 INFO("Message length %d, version %d, type RTM_DELETE, index %d",
1348 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1349 addr
= (addr_t
*)((&message
->if2
) + 1);
1352 INFO("Message length %d, version %d, type RTM_CHANGE, index %d",
1353 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1354 addr
= (addr_t
*)((&message
->if2
) + 1);
1357 INFO("Message length %d, version %d, type %d", message
->len
, message
->route
.rtm_version
,
1358 message
->route
.rtm_type
);
1365 route_callback(io_t
*NONNULL io
, void *__unused context
)
1368 route_message_t message
;
1370 rv
= read(io
->fd
, &message
, sizeof message
);
1372 ERROR("route_callback: read returned " PUB_S_SRP
, strerror(errno
));
1375 } else if (rv
== 0) {
1376 ERROR("route_callback: read returned 0");
1380 // Process the message.
1381 route_message(io
, &message
);
1387 route_entry(struct rt_msghdr2
*route
)
1396 #define NUM_SYSCTL_ARGS 6
1397 int sysctl_args
[NUM_SYSCTL_ARGS
];
1398 char *table
, *next_route
, *end
;
1399 struct rt_msghdr2
*route
;
1402 sysctl_args
[0] = CTL_NET
;
1403 sysctl_args
[1] = PF_ROUTE
;
1406 sysctl_args
[4] = NET_RT_DUMP2
;
1409 rv
= sysctl(sysctl_args
, NUM_SYSCTL_ARGS
, NULL
, &table_size
, NULL
, 0);
1411 ERROR("route_fetch: sysctl failed getting routing table dump estimate: " PUB_S_SRP
, strerror(errno
));
1415 table
= malloc(table_size
);
1416 if (table
== NULL
) {
1417 ERROR("No memory for routing table of size %zu", table_size
);
1421 rv
= sysctl(sysctl_args
, NUM_SYSCTL_ARGS
, table
, &table_size
, NULL
, 0);
1423 ERROR("route_fetch: sysctl failed getting routing table dump: " PUB_S_SRP
, strerror(errno
));
1427 end
= table
+ table_size
;
1428 for (next_route
= table
; next_route
< end
; next_route
= next_route
+ route
->rtm_msglen
) {
1429 route
= (struct rt_msghdr2
*)next_route
;
1430 if (route
->rtm_msglen
+ next_route
> end
) {
1431 INFO("Bogus routing table--last route goes past end of buffer.");
1439 start_route_listener(void)
1441 int sock
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
);
1443 ERROR("Unable to listen for link status change events: " PUB_S_SRP
, strerror(errno
));
1447 io_t
*io
= ioloop_file_descriptor_create(sock
, NULL
, NULL
);
1449 ERROR("No memory for route I/O structure.");
1455 static uint8_t subscriptions
[] = { RTM_NEWADDR
, RTM_DELADDR
, RTM_IFINFO
, RTM_IFINFO2
};
1456 if (setsockopt(routefd
, PF_ROUTE
, RO_MSGFILTER
, &subscriptions
, (socklen_t
)sizeof(subscriptions
)) < 0) {
1457 ERROR("Unable to set routing socket subscriptions.");
1461 ioloop_add_reader(io
, route_callback
);
1466 #endif // MONITOR_ROUTING_SOCKET
1468 #if defined(USE_IPCONFIGURATION_SERVICE)
1470 dict_add_string_as_array(CFMutableDictionaryRef dict
, CFStringRef prop_name
, const char * str
)
1473 CFStringRef prop_val
;
1478 prop_val
= CFStringCreateWithCString(NULL
, str
, kCFStringEncodingUTF8
);
1479 array
= CFArrayCreate(NULL
, (const void **)&prop_val
, 1, &kCFTypeArrayCallBacks
);
1480 CFRelease(prop_val
);
1481 CFDictionarySetValue(dict
, prop_name
, array
);
1487 dict_add_int_as_array(CFMutableDictionaryRef dict
, CFStringRef prop_name
,
1493 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &int_val
);
1494 array
= CFArrayCreate(NULL
, (const void **)&num
, 1, &kCFTypeArrayCallBacks
);
1496 CFDictionarySetValue(dict
, prop_name
, array
);
1501 static CFDictionaryRef
1502 ipconfig_options_dict_create(CFDictionaryRef config_dict
)
1504 return CFDictionaryCreate(NULL
, (const void **)&kIPConfigurationServiceOptionIPv6Entity
,
1505 (const void **)&config_dict
, 1, &kCFTypeDictionaryKeyCallBacks
,
1506 &kCFTypeDictionaryValueCallBacks
);
1510 ipconfig_service_changed(interface_t
* interface
)
1512 CFDictionaryRef service_info
;
1514 if (interface
->ip_configuration_service
== NULL
) {
1515 INFO("ipconfig_service_changed: ip_configuration_service is NULL");
1518 service_info
= IPConfigurationServiceCopyInformation(interface
->ip_configuration_service
);
1519 if (service_info
== NULL
) {
1520 INFO("ipconfig_service_changed: IPConfigurationService on " PUB_S_SRP
" is incomplete", interface
->name
);
1523 INFO("ipconfig_service_changed: IPConfigurationService on " PUB_S_SRP
" is ready", interface
->name
);
1524 CFRelease(service_info
);
1526 // Now that the prefix is configured on the interface, we can start advertising it.
1527 interface
->on_link_prefix_configured
= true;
1528 routing_policy_evaluate(interface
, true);
1536 ipconfig_service_callback(SCDynamicStoreRef __unused session
, CFArrayRef __unused changes
,
1539 interface_t
* interface
= (interface_t
*)info
;
1541 ipconfig_service_changed(interface
);
1546 monitor_ipconfig_service(interface_t
* interface
)
1548 SCDynamicStoreContext context
= {
1553 .copyDescription
= NULL
1556 SCDynamicStoreRef store
;
1557 CFStringRef store_key
;
1559 if (interface
->ip_configuration_store
!= NULL
) {
1560 INFO("Releasing old SCDynamicStore object for " PUB_S_SRP
, interface
->name
);
1561 SCDynamicStoreSetDispatchQueue(interface
->ip_configuration_store
, NULL
);
1562 CFRelease(interface
->ip_configuration_store
);
1563 interface
->ip_configuration_store
= NULL
;
1566 #define OUR_IDENTIFIER CFSTR("ThreadBorderRouter")
1567 context
.info
= interface
;
1568 store
= SCDynamicStoreCreate(NULL
, OUR_IDENTIFIER
,
1569 ipconfig_service_callback
, &context
);
1570 store_key
= IPConfigurationServiceGetNotificationKey(interface
->ip_configuration_service
);
1571 keys
= CFArrayCreate(NULL
, (const void * *)&store_key
,
1573 &kCFTypeArrayCallBacks
);
1574 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1577 /* avoid race with being notified */
1578 ipconfig_service_changed(interface
);
1579 SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue());
1580 interface
->ip_configuration_store
= (void *)store
;
1584 start_ipconfig_service(interface_t
*interface
, const char *ip6addr_str
)
1586 CFMutableDictionaryRef config_dict
;
1587 CFStringRef interface_name
;
1588 CFDictionaryRef options
;
1590 if (interface
->ip_configuration_service
!= NULL
) {
1591 INFO("start_ipconfig_service: releasing old IPConfigurationService object for " PUB_S_SRP
, interface
->name
);
1592 CFRelease(interface
->ip_configuration_service
);
1593 interface
->ip_configuration_service
= NULL
;
1596 // Create an IPv6 entity dictionary with ConfigMethod, Addresses, and PrefixLength properties
1597 config_dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1598 CFDictionarySetValue(config_dict
, kSCPropNetIPv6ConfigMethod
, kSCValNetIPv6ConfigMethodManual
);
1599 #define PREFIX_LENGTH 64
1600 dict_add_string_as_array(config_dict
, kSCPropNetIPv6Addresses
, ip6addr_str
);
1601 dict_add_int_as_array(config_dict
, kSCPropNetIPv6PrefixLength
, PREFIX_LENGTH
);
1602 options
= ipconfig_options_dict_create(config_dict
);
1603 CFRelease(config_dict
);
1604 interface_name
= CFStringCreateWithCString(NULL
, interface
->name
, kCFStringEncodingUTF8
);
1605 interface
->ip_configuration_service
= IPConfigurationServiceCreate(interface_name
, options
);
1606 CFRelease(interface_name
);
1608 if (interface
->ip_configuration_service
== NULL
) {
1609 ERROR("start_ipconfig_service: IPConfigurationServiceCreate on " PUB_S_SRP
" failed", interface
->name
);
1612 monitor_ipconfig_service(interface
);
1613 struct in6_addr ip6addr
;
1614 int ret
= inet_pton(AF_INET6
, ip6addr_str
, ip6addr
.s6_addr
);
1616 SEGMENTED_IPv6_ADDR_GEN_SRP(ip6addr
.s6_addr
, ip6addr_buf
);
1617 INFO("start_ipconfig_service: IPConfigurationServiceCreate on " PRI_S_SRP
"/" PRI_SEGMENTED_IPv6_ADDR_SRP
1618 " succeeded", interface
->name
, SEGMENTED_IPv6_ADDR_PARAM_SRP(ip6addr
.s6_addr
, ip6addr_buf
));
1621 return (interface
->ip_configuration_service
!= NULL
);
1624 #elif defined(CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG)
1626 link_route_done(void *context
, int status
, const char *error
)
1628 interface_t
*interface
= context
;
1630 if (error
!= NULL
) {
1631 ERROR("link_route_done on " PUB_S_SRP
": " PUB_S_SRP
, interface
->name
, error
);
1633 INFO("link_route_done on " PUB_S_SRP
": %d.", interface
->name
, status
);
1635 ioloop_subproc_release(link_route_adder_process
);
1636 // Now that the on-link prefix is configured, time for a policy re-evaluation.
1637 interface
->on_link_prefix_configured
= true;
1638 routing_policy_evaluate(interface
, true);
1643 interface_prefix_configure(struct in6_addr prefix
, interface_t
*interface
)
1647 sock
= socket(PF_INET6
, SOCK_DGRAM
, 0);
1649 ERROR("interface_prefix_configure: socket(PF_INET6, SOCK_DGRAM, 0) failed " PUB_S_SRP
": " PUB_S_SRP
,
1650 interface
->name
, strerror(errno
));
1653 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
1654 struct in6_addr interface_address
= prefix
;
1655 char addrbuf
[INET6_ADDRSTRLEN
];
1656 interface_address
.s6_addr
[15] = 1;
1657 inet_ntop(AF_INET6
, &interface_address
, addrbuf
, INET6_ADDRSTRLEN
);
1658 #if defined (USE_IPCONFIGURATION_SERVICE)
1659 if (!start_ipconfig_service(interface
, addrbuf
)) {
1663 #elif defined(CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG)
1664 char *args
[] = { "set", interface
->name
, "MANUAL-V6", addrbuf
, "64" };
1666 INFO("interface_prefix_configure: /sbin/ipconfig " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" "
1667 PUB_S_SRP
, args
[0], args
[1], args
[2], args
[3], args
[4]);
1668 link_route_adder_process
= ioloop_subproc("/usr/sbin/ipconfig", args
, 5, link_route_done
, interface
, NULL
);
1669 if (link_route_adder_process
== NULL
) {
1670 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address
.s6_addr
, if_addr_buf
);
1671 ERROR("interface_prefix_configure: unable to set interface address for " PUB_S_SRP
" to "
1672 PRI_SEGMENTED_IPv6_ADDR_SRP
".", interface
->name
,
1673 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address
.s6_addr
, if_addr_buf
));
1676 struct in6_aliasreq alias_request
;
1677 memset(&alias_request
, 0, sizeof(alias_request
));
1678 strlcpy(alias_request
.ifra_name
, interface
->name
, IFNAMSIZ
);
1679 alias_request
.ifra_addr
.sin6_family
= AF_INET6
;
1680 alias_request
.ifra_addr
.sin6_len
= sizeof(alias_request
.ifra_addr
);
1681 memcpy(&alias_request
.ifra_addr
.sin6_addr
, &interface_address
, sizeof(alias_request
.ifra_addr
.sin6_addr
));
1682 alias_request
.ifra_prefixmask
.sin6_len
= sizeof(alias_request
.ifra_addr
);
1683 alias_request
.ifra_prefixmask
.sin6_family
= AF_INET6
;
1684 memset(&alias_request
.ifra_prefixmask
.sin6_addr
, 0xff, 8); // /64.
1685 alias_request
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
; // seconds, I hope?
1686 alias_request
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
; // seconds, I hope?
1687 ret
= ioctl(sock
, SIOCAIFADDR_IN6
, &alias_request
);
1689 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address
.s6_addr
, if_addr_buf
);
1690 ERROR("interface_prefix_configure: can't configure static address " PRI_SEGMENTED_IPv6_ADDR_SRP
" on " PUB_S_SRP
1691 ": " PUB_S_SRP
, SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address
.s6_addr
, if_addr_buf
), interface
->name
,
1694 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address
.s6_addr
, if_addr_buf
);
1695 INFO("interface_prefix_configure: added address " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PUB_S_SRP
,
1696 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address
.s6_addr
, if_addr_buf
), interface
->name
);
1698 #endif // CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG
1701 #endif // CONFIGURE_STATIC_INTERFACE_ADDRESSES
1704 #ifdef USE_SYSCTL_COMMMAND_TO_ENABLE_FORWARDING
1706 thread_forwarding_done(void *__unused context
, int status
, const char *error
)
1708 if (error
!= NULL
) {
1709 ERROR("thread_forwarding_done: " PUB_S_SRP
, error
);
1711 INFO("thread_forwarding_done: %d.", status
);
1713 ioloop_subproc_release(thread_forwarding_setter_process
);
1717 set_thread_forwarding(void)
1719 char *args
[] = { "-w", "net.inet6.ip6.forwarding=1" };
1721 INFO("/usr/sbin/sysctl " PUB_S_SRP
" " PUB_S_SRP
, args
[0], args
[1]);
1722 thread_forwarding_setter_process
= ioloop_subproc("/usr/sbin/sysctl", args
, 2, thread_forwarding_done
,
1724 if (thread_forwarding_setter_process
== NULL
) {
1725 ERROR("Unable to set thread forwarding enabled.");
1732 set_thread_forwarding(void)
1735 int ret
= sysctlbyname("net.inet6.ip6.forwarding", NULL
, 0, &wun
, sizeof(wun
));
1737 ERROR("set_thread_forwarding: " PUB_S_SRP
, strerror(errno
));
1739 INFO("Enabled IPv6 forwarding.");
1742 #endif // USE_SYSCTL_COMMMAND_TO_ENABLE_FORWARDING
1744 #ifdef NEED_THREAD_RTI_SETTER
1746 thread_rti_done(void *__unused context
, int status
, const char *error
)
1748 if (error
!= NULL
) {
1749 ERROR("thread_rti_done: " PUB_S_SRP
, error
);
1751 INFO("thread_rti_done: %d.", status
);
1753 ioloop_subproc_release(thread_rti_setter_process
);
1757 set_thread_rti(void)
1759 char *args
[] = { "-w", "net.inet6.icmp6.nd6_process_rti=1" };
1760 thread_rti_setter_process
= ioloop_subproc("/usr/sbin/sysctl", args
, 2, thread_rti_done
,
1762 if (thread_rti_setter_process
== NULL
) {
1763 ERROR("Unable to set thread rti enabled.");
1768 #if TARGET_OS_TV && !defined(RA_TESTER)
1769 #ifdef ADD_PREFIX_WITH_WPANCTL
1771 thread_prefix_done(void *__unused context
, int status
, const char *error
)
1773 if (error
!= NULL
) {
1774 ERROR("thread_prefix_done: " PUB_S_SRP
, error
);
1776 interface_t
*interface
;
1778 INFO("thread_prefix_done: %d.", status
);
1779 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1780 if (!interface
->inactive
) {
1781 interface_beacon_schedule(interface
, 0);
1785 ioloop_subproc_release(thread_prefix_adder_process
);
1790 cti_add_prefix_callback(void *__unused context
, cti_status_t status
)
1792 interface_t
*interface
;
1793 INFO("cti_add_prefix_callback: %d", status
);
1794 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1795 if (!interface
->inactive
) {
1796 interface_beacon_schedule(interface
, 0);
1801 static thread_prefix_t
*
1802 get_advertised_thread_prefix(void)
1804 if (published_thread_prefix
!= NULL
) {
1805 return published_thread_prefix
;
1807 return adopted_thread_prefix
;
1813 set_thread_prefix(void)
1815 char addrbuf
[INET6_ADDRSTRLEN
];
1816 thread_prefix_t
*advertised_thread_prefix
= get_advertised_thread_prefix();
1817 if (advertised_thread_prefix
== NULL
) {
1818 ERROR("set_thread_prefix: no advertised thread prefix.");
1821 SEGMENTED_IPv6_ADDR_GEN_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
);
1822 inet_ntop(AF_INET6
, &advertised_thread_prefix
->prefix
, addrbuf
, sizeof addrbuf
);
1823 #ifdef ADD_PREFIX_WITH_WPANCTL
1824 char *args
[] = { "add-prefix", "--stable", "--preferred", "--slaac", "--default-route", "--on-mesh", addrbuf
};
1825 INFO("/usr/local/bin/wpanctl " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" "
1826 PRI_SEGMENTED_IPv6_ADDR_SRP
, args
[0], args
[1], args
[2], args
[3], args
[4], args
[5],
1827 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
));
1828 thread_prefix_adder_process
= ioloop_subproc("/usr/local/bin/wpanctl", args
, 7, thread_prefix_done
,
1830 if (thread_prefix_adder_process
== NULL
) {
1831 ERROR("Unable to add thread interface prefix.");
1834 INFO("add_prefix(true, true, true, true, " PRI_SEGMENTED_IPv6_ADDR_SRP
")",
1835 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
));
1836 int status
= cti_add_prefix(NULL
, cti_add_prefix_callback
, dispatch_get_main_queue(),
1837 &advertised_thread_prefix
->prefix
, advertised_thread_prefix
->prefix_len
,
1838 true, true, true, true);
1840 ERROR("Unable to add thread interface prefix.");
1844 #endif // TARGET_OS_TV && !RA_TESTER
1847 router_advertisement_send(interface_t
*interface
)
1850 dns_towire_state_t towire
;
1852 // Thread blocks RAs so no point sending them.
1853 if (interface
->inactive
1855 || interface
->is_thread
1861 #define MAX_ICMP_MESSAGE 1280
1862 message
= malloc(MAX_ICMP_MESSAGE
);
1863 if (message
== NULL
) {
1864 ERROR("Unable to construct ICMP Router Advertisement: no memory");
1868 // Construct the ICMP header and options for each interface.
1869 memset(&towire
, 0, sizeof towire
);
1871 towire
.lim
= message
+ MAX_ICMP_MESSAGE
;
1873 // Construct the ICMP header.
1874 // We use the DNS message construction functions because it's easy; probably should just make
1875 // the towire functions more generic.
1876 dns_u8_to_wire(&towire
, ND_ROUTER_ADVERT
); // icmp6_type
1877 dns_u8_to_wire(&towire
, 0); // icmp6_code
1878 dns_u16_to_wire(&towire
, 0); // The kernel computes the checksum (we don't technically have it).
1879 dns_u8_to_wire(&towire
, 0); // Hop limit, we don't set.
1880 dns_u8_to_wire(&towire
, 0); // Flags. We don't offer DHCP, so We set neither the M nor the O bit.
1881 // We are not a home agent, so no H bit. Lifetime is 0, so Prf is 0.
1882 #ifdef ROUTER_LIFETIME_HACK
1883 dns_u16_to_wire(&towire
, 1800); // Router lifetime, hacked. This shouldn't ever be enabled.
1886 // Advertise a default route on the simulated thread network
1887 if (!strcmp(interface
->name
, thread_interface_name
)) {
1888 dns_u16_to_wire(&towire
, 1800); // Router lifetime for default route
1891 dns_u16_to_wire(&towire
, 0); // Router lifetime for non-default default route(s).
1895 #endif // ROUTER_LIFETIME_HACK
1896 dns_u32_to_wire(&towire
, 0); // Reachable time for NUD, we have no opinion on this.
1897 dns_u32_to_wire(&towire
, 0); // Retransmission timer, again we have no opinion.
1899 // Send Source link-layer address option
1900 if (interface
->have_link_layer_address
) {
1901 dns_u8_to_wire(&towire
, ND_OPT_SOURCE_LINKADDR
);
1902 dns_u8_to_wire(&towire
, 1); // length / 8
1903 dns_rdata_raw_data_to_wire(&towire
, &interface
->link_layer
, sizeof(interface
->link_layer
));
1904 INFO("Advertising source lladdr " PRI_MAC_ADDR_SRP
" on " PUB_S_SRP
, MAC_ADDR_PARAM_SRP(interface
->link_layer
),
1909 // Send MTU of 1280 for Thread?
1910 if (interface
->is_thread
) {
1911 dns_u8_to_wire(&towire
, ND_OPT_MTU
);
1912 dns_u8_to_wire(&towire
, 1); // length / 8
1913 dns_u32_to_wire(&towire
, 1280);
1914 INFO("Advertising MTU of 1280 on " PUB_S_SRP
, interface
->name
);
1918 // Send Prefix Information option if there's no IPv6 on the link.
1919 if (interface
->advertise_ipv6_prefix
) {
1920 dns_u8_to_wire(&towire
, ND_OPT_PREFIX_INFORMATION
);
1921 dns_u8_to_wire(&towire
, 4); // length / 8
1922 dns_u8_to_wire(&towire
, 64); // On-link prefix is always 64 bits
1923 dns_u8_to_wire(&towire
, ND_OPT_PI_FLAG_ONLINK
| ND_OPT_PI_FLAG_AUTO
); // On link, autoconfig
1924 dns_u32_to_wire(&towire
, interface
->valid_lifetime
);
1925 dns_u32_to_wire(&towire
, interface
->preferred_lifetime
);
1926 dns_u32_to_wire(&towire
, 0); // Reserved
1927 dns_rdata_raw_data_to_wire(&towire
, &interface
->ipv6_prefix
, sizeof interface
->ipv6_prefix
);
1928 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
);
1929 INFO("Advertising on-link prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" on " PUB_S_SRP
,
1930 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
), interface
->name
);
1933 #ifndef ND_OPT_ROUTE_INFORMATION
1934 #define ND_OPT_ROUTE_INFORMATION 24
1936 // In principle we can either send routes to links that are reachable by this router,
1937 // or just advertise a router to the entire ULA /48. In theory it doesn't matter
1938 // which we do; if we support HNCP at some point we probably need to be specific, but
1939 // for now being general is fine because we have no way to share a ULA.
1940 // Unfortunately, some RIO implementations do not work with specific routes, so for now
1941 // We are doing it the easy way and just advertising the /48.
1942 #define SEND_INTERFACE_SPECIFIC_RIOS 1
1943 #ifdef SEND_INTERFACE_SPECIFIC_RIOS
1945 // If neither ROUTE_BETWEEN_NON_THREAD_LINKS nor RA_TESTER are defined, then we never want to
1946 // send an RIO other than for the thread network prefix.
1947 #if defined (ROUTE_BETWEEN_NON_THREAD_LINKS) || defined(RA_TESTER)
1948 interface_t
*ifroute
;
1949 // Send Route Information option for other interfaces.
1950 for (ifroute
= interfaces
; ifroute
; ifroute
= ifroute
->next
) {
1951 if (ifroute
->inactive
) {
1956 partition_can_provide_routing
&&
1958 ifroute
->advertise_ipv6_prefix
&&
1959 #ifdef SEND_ON_LINK_ROUTE
1960 // In theory we don't want to send RIO for the on-link prefix, but there's this bug, see.
1963 ifroute
!= interface
&&
1966 // For the RA tester, we don't need to send an RIO to the thread network because we're the
1967 // default router for that network.
1968 strcmp(interface
->name
, thread_interface_name
)
1974 dns_u8_to_wire(&towire
, ND_OPT_ROUTE_INFORMATION
);
1975 dns_u8_to_wire(&towire
, 2); // length / 8
1976 dns_u8_to_wire(&towire
, 64); // Interface prefixes are always 64 bits
1977 dns_u8_to_wire(&towire
, 0); // There's no reason at present to prefer one Thread BR over another
1978 dns_u32_to_wire(&towire
, 1800); // Route lifetime 1800 seconds (30 minutes)
1979 dns_rdata_raw_data_to_wire(&towire
, &ifroute
->ipv6_prefix
, 8); // /64 requires 8 bytes.
1980 SEGMENTED_IPv6_ADDR_GEN_SRP(ifroute
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
);
1981 INFO("Sending route to " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%" PUB_S_SRP
" on " PUB_S_SRP
,
1982 SEGMENTED_IPv6_ADDR_PARAM_SRP(ifroute
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
),
1983 ifroute
->name
, interface
->name
);
1986 #endif // ROUTE_BETWEEN_NON_THREAD_LINKS || RA_TESTER
1989 // Send route information option for thread prefix
1990 thread_prefix_t
*advertised_thread_prefix
= get_advertised_thread_prefix();
1991 if (advertised_thread_prefix
!= NULL
) {
1992 dns_u8_to_wire(&towire
, ND_OPT_ROUTE_INFORMATION
);
1993 dns_u8_to_wire(&towire
, 2); // length / 8
1994 dns_u8_to_wire(&towire
, 64); // Interface prefixes are always 64 bits
1995 dns_u8_to_wire(&towire
, 0); // There's no reason at present to prefer one Thread BR over another
1996 dns_u32_to_wire(&towire
, 1800); // Route lifetime 1800 seconds (30 minutes)
1997 dns_rdata_raw_data_to_wire(&towire
, &advertised_thread_prefix
->prefix
, 8); // /64 requires 8 bytes.
1998 SEGMENTED_IPv6_ADDR_GEN_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
);
1999 INFO("Sending route to " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%" PUB_S_SRP
" on " PUB_S_SRP
,
2000 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
),
2001 thread_interface_name
, interface
->name
);
2005 #ifndef SKIP_SLASH_48
2006 dns_u8_to_wire(&towire
, ND_OPT_ROUTE_INFORMATION
);
2007 dns_u8_to_wire(&towire
, 3); // length / 8
2008 dns_u8_to_wire(&towire
, 48); // ULA prefixes are always 48 bits
2009 dns_u8_to_wire(&towire
, 0); // There's no reason at present to prefer one Thread BR over another
2010 dns_u32_to_wire(&towire
, 1800); // Route lifetime 1800 seconds (30 minutes)
2011 dns_rdata_raw_data_to_wire(&towire
, &ula_prefix
, 16); // /48 requires 16 bytes
2012 #endif // SKIP_SLASH_48
2013 #endif // SEND_INTERFACE_SPECIFIC_RIOS
2016 ERROR("No space in ICMP output buffer for " PUB_S_SRP
" at route.c:%d", interface
->name
, towire
.line
);
2019 icmp_send(message
, towire
.p
- message
, interface
, &in6addr_linklocal_allnodes
);
2025 router_solicit_send(interface_t
*interface
)
2028 dns_towire_state_t towire
;
2030 // Thread blocks RSs so no point sending them.
2031 if (interface
->inactive
2033 || interface
->is_thread
2039 #define MAX_ICMP_MESSAGE 1280
2040 message
= malloc(MAX_ICMP_MESSAGE
);
2041 if (message
== NULL
) {
2042 ERROR("Unable to construct ICMP Router Advertisement: no memory");
2046 // Construct the ICMP header and options for each interface.
2047 memset(&towire
, 0, sizeof towire
);
2049 towire
.lim
= message
+ MAX_ICMP_MESSAGE
;
2051 // Construct the ICMP header.
2052 // We use the DNS message construction functions because it's easy; probably should just make
2053 // the towire functions more generic.
2054 dns_u8_to_wire(&towire
, ND_ROUTER_SOLICIT
); // icmp6_type
2055 dns_u8_to_wire(&towire
, 0); // icmp6_code
2056 dns_u16_to_wire(&towire
, 0); // The kernel computes the checksum (we don't technically have it).
2057 dns_u32_to_wire(&towire
, 0); // Reserved32
2059 // Send Source link-layer address option
2060 if (interface
->have_link_layer_address
) {
2061 dns_u8_to_wire(&towire
, ND_OPT_SOURCE_LINKADDR
);
2062 dns_u8_to_wire(&towire
, 1); // length / 8
2063 dns_rdata_raw_data_to_wire(&towire
, &interface
->link_layer
, sizeof(interface
->link_layer
));
2067 ERROR("No space in ICMP output buffer for " PUB_S_SRP
" at route.c:%d", interface
->name
, towire
.line
);
2069 icmp_send(message
, towire
.p
- message
, interface
, &in6addr_linklocal_allrouters
);
2075 icmp_send(uint8_t *message
, size_t length
, interface_t
*interface
, const struct in6_addr
*destination
)
2078 socklen_t cmsg_length
= CMSG_SPACE(sizeof(struct in6_pktinfo
)) + CMSG_SPACE(sizeof (int));
2079 uint8_t *cmsg_buffer
;
2080 struct msghdr msg_header
;
2081 struct cmsghdr
*cmsg_pointer
;
2082 struct in6_pktinfo
*packet_info
;
2083 int hop_limit
= 255;
2085 struct sockaddr_in6 dest
;
2087 // Make space for the control message buffer.
2088 cmsg_buffer
= malloc(cmsg_length
);
2089 if (cmsg_buffer
== NULL
) {
2090 ERROR("Unable to construct ICMP Router Advertisement: no memory");
2095 memset(&dest
, 0, sizeof(dest
));
2096 dest
.sin6_family
= AF_INET6
;
2097 dest
.sin6_scope_id
= interface
->index
;
2098 dest
.sin6_len
= sizeof(dest
);
2099 msg_header
.msg_namelen
= sizeof(dest
);
2100 dest
.sin6_addr
= *destination
;
2102 msg_header
.msg_name
= &dest
;
2103 iov
.iov_base
= message
;
2104 iov
.iov_len
= length
;
2105 msg_header
.msg_iov
= &iov
;
2106 msg_header
.msg_iovlen
= 1;
2107 msg_header
.msg_control
= cmsg_buffer
;
2108 msg_header
.msg_controllen
= cmsg_length
;
2110 // Specify the interface
2111 cmsg_pointer
= CMSG_FIRSTHDR(&msg_header
);
2112 cmsg_pointer
->cmsg_level
= IPPROTO_IPV6
;
2113 cmsg_pointer
->cmsg_type
= IPV6_PKTINFO
;
2114 cmsg_pointer
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
2115 packet_info
= (struct in6_pktinfo
*)CMSG_DATA(cmsg_pointer
);
2116 memset(packet_info
, 0, sizeof(*packet_info
));
2117 packet_info
->ipi6_ifindex
= interface
->index
;
2119 // Router advertisements and solicitations have a hop limit of 255
2120 cmsg_pointer
= CMSG_NXTHDR(&msg_header
, cmsg_pointer
);
2121 cmsg_pointer
->cmsg_level
= IPPROTO_IPV6
;
2122 cmsg_pointer
->cmsg_type
= IPV6_HOPLIMIT
;
2123 cmsg_pointer
->cmsg_len
= CMSG_LEN(sizeof(int));
2124 memcpy(CMSG_DATA(cmsg_pointer
), &hop_limit
, sizeof(hop_limit
));
2127 rv
= sendmsg(icmp_listener
.io_state
->fd
, &msg_header
, 0);
2129 uint8_t *in6_addr_bytes
= ((struct sockaddr_in6
*)(msg_header
.msg_name
))->sin6_addr
.s6_addr
;
2130 SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_bytes
, in6_addr_buf
);
2131 ERROR("icmp_send: sending " PUB_S_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
" on interface " PUB_S_SRP
2132 " index %d: " PUB_S_SRP
, message
[0] == ND_ROUTER_SOLICIT
? "solicit" : "advertise",
2133 SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_bytes
, in6_addr_buf
),
2134 interface
->name
, interface
->index
, strerror(errno
));
2135 } else if ((size_t)rv
!= iov
.iov_len
) {
2136 ERROR("icmp_send: short send to interface " PUB_S_SRP
": %zd < %zd", interface
->name
, rv
, iov
.iov_len
);
2142 post_solicit_policy_evaluate(void *context
)
2144 interface_t
*interface
= context
;
2145 INFO("Done waiting for router discovery to finish on " PUB_S_SRP
, interface
->name
);
2146 interface
->router_discovery_complete
= true;
2147 interface
->router_discovery_in_progress
= false;
2148 flush_stale_routers(interface
, ioloop_timenow());
2150 // See if we need a new prefix on the interface.
2151 interface_prefix_evaluate(interface
);
2153 routing_policy_evaluate(interface
, true);
2154 // Always clear out need_reconfigure_prefix when router_discovery_complete is set to true.
2155 interface
->need_reconfigure_prefix
= false;
2159 dump_network_signature(char *buffer
, size_t buffer_size
, const uint8_t *signature
, long length
)
2161 char *hexp
= buffer
;
2163 size_t left
= buffer_size
;
2167 strlcpy(buffer
, "<NULL>", buffer_size
);
2170 for (i
= 0; i
< length
; i
++) {
2171 snprintf(hexp
, left
, "%02x", signature
[i
]);
2179 network_link_finalize(network_link_t
*link
)
2181 if (link
->signature
!= NULL
) {
2182 free(link
->signature
);
2187 #define network_link_create(signature, length) network_link_create_(signature, length, __FILE__, __LINE__);
2188 static network_link_t
*
2189 network_link_create_(const uint8_t *signature
, int length
, const char *file
, int line
)
2191 network_link_t
*link
= calloc(1, sizeof(*link
));
2193 if (signature
!= NULL
) {
2195 link
->signature
= malloc(length
);
2196 if (link
->signature
== NULL
) {
2197 INFO("network_link_create: no memory for signature.");
2201 memcpy(link
->signature
, signature
, length
);
2202 link
->signature_length
= length
;
2210 static CFDictionaryRef
2211 network_link_dictionary_copy(network_link_t
*link
)
2213 CFDictionaryRef dictionary
= NULL
;
2215 err
= CFPropertyListCreateFormatted(kCFAllocatorDefault
, &dictionary
,
2222 link
->signature
, (int)link
->signature_length
,
2223 link
->prefix_number
);
2226 ERROR("CFPropertyListCreateFormatted failed: %d", err
);
2231 typedef struct network_link_parse_state network_link_parse_state_t
;
2232 struct network_link_parse_state
{
2233 network_link_t
*NONNULL link
;
2237 bool prefix_number
: 1;
2241 network_link_parse(const void *key
, const void *value
, void *context
)
2243 network_link_parse_state_t
*parse_state
= context
;
2246 if (parse_state
->fail
) {
2249 if (CFGetTypeID(key
) != CFStringGetTypeID()) {
2250 ERROR("network_link_parse: dictionary key not a string.");
2251 parse_state
->fail
= true;
2255 if (CFStringCompare(key
, CFSTR("last-seen"), 0) == kCFCompareEqualTo
) {
2256 // We store the last-seen time as a uint64 encoded as a string, because there is no uint64 CFNumber type.
2257 // We store the prefix-number time as a CFNumber because it's a uint16_t.
2258 if (CFGetTypeID(value
) != CFNumberGetTypeID() ||
2259 !CFNumberGetValue(value
, kCFNumberSInt64Type
, &last_seen
))
2261 ERROR("network_link_parse: last-seen is not a valid CFNumber");
2262 parse_state
->fail
= true;
2264 // For some reason CFNumber doesn't support uint64_t, but we are assuming that since we are copying this
2265 // unchanged, there will be no error introduced by this case.
2266 // CFProperyListCreateFormatted supports uint64_t, probably by doing the same thing.
2267 parse_state
->link
->last_seen
= (uint64_t)last_seen
;
2268 parse_state
->last_seen
= true;
2270 } else if (CFStringCompare(key
, CFSTR("signature"), 0) == kCFCompareEqualTo
) {
2271 const uint8_t *data_buffer
;
2274 // We store the signature as CFData.
2275 if (CFGetTypeID(value
) != CFDataGetTypeID()) {
2276 ERROR("network_link_parse: Unable to get CFData for signature because it's not CFData.");
2277 parse_state
->fail
= true;
2279 data_buffer
= CFDataGetBytePtr(value
);
2280 data_length
= CFDataGetLength(value
);
2281 if (data_length
< 1) {
2282 parse_state
->link
->signature_length
= 0;
2283 parse_state
->link
->signature
= NULL
;
2284 parse_state
->signature
= true;
2286 parse_state
->link
->signature_length
= data_length
;
2287 parse_state
->link
->signature
= malloc(data_length
);
2288 if (parse_state
->link
->signature
== NULL
) {
2289 ERROR("network_link_parse: No memory for signature.");
2290 parse_state
->fail
= true;
2292 memcpy(parse_state
->link
->signature
, data_buffer
, data_length
);
2293 parse_state
->signature
= true;
2297 } else if (CFStringCompare(key
, CFSTR("prefix-number"), 0) == kCFCompareEqualTo
) {
2298 // We store the prefix-number time as a CFNumber because it's a uint16_t.
2299 if (CFGetTypeID(value
) != CFNumberGetTypeID() ||
2300 !CFNumberGetValue(value
, kCFNumberSInt32Type
, &parse_state
->link
->prefix_number
))
2302 ERROR("network_link_parse: prefix-number is not a valid CFNumber");
2303 parse_state
->fail
= true;
2304 } else if (parse_state
->link
->prefix_number
< 0 || parse_state
->link
->prefix_number
> UINT16_MAX
) {
2305 ERROR("network_link_parse: Invalid prefix-number: %" PRIu32
, parse_state
->link
->prefix_number
);
2306 parse_state
->fail
= true;
2308 parse_state
->prefix_number
= true;
2311 char key_buffer
[64];
2312 if (!CFStringGetCString(key
, key_buffer
, sizeof(key_buffer
), kCFStringEncodingUTF8
)) {
2313 INFO("Unexpected network link element dictionary key, but can't decode key");
2315 INFO("Unexpected network link element dictionary key " PUB_S_SRP
, key_buffer
);
2317 parse_state
->fail
= true;
2322 network_link_apply(const void *value
, void *context
)
2324 bool *success
= context
;
2325 CFDictionaryRef values
= value
;
2326 network_link_parse_state_t parse_state
;
2329 if (*success
== false) {
2333 memset(&parse_state
, 0, sizeof parse_state
);
2334 parse_state
.link
= network_link_create(NULL
, 0);
2335 if (parse_state
.link
== NULL
) {
2336 ERROR("network_link_apply: no memory for link");
2341 // Parse the dictionary into the structure.
2342 CFDictionaryApplyFunction(values
, network_link_parse
, &parse_state
);
2344 // Should have gotten three fields: last_seen, signature, prefix_number
2345 if (!parse_state
.last_seen
) {
2346 ERROR("network_link_apply: expecting last-seen");
2347 parse_state
.fail
= true;
2349 if (!parse_state
.signature
) {
2350 ERROR("network_link_apply: expecting signature");
2351 parse_state
.fail
= true;
2353 if (!parse_state
.prefix_number
) {
2354 ERROR("network_link_apply: expecting prefix-number");
2355 parse_state
.fail
= true;
2357 if (parse_state
.fail
) {
2359 RELEASE_HERE(parse_state
.link
, network_link_finalize
);
2363 dump_network_signature(hexbuf
, sizeof hexbuf
, parse_state
.link
->signature
, parse_state
.link
->signature_length
);
2365 // If the link signature hasn't been seen in over a week, there is no need to remember it. If no new links are
2366 // seen, an old signature could persist for much longer than a week, but this is okay--the goal here is to prevent
2367 // the link array from growing without bound, and whenver a link signature is added, the array is rewritte, at
2368 // which point the old link signatures will be erased.
2369 if (ioloop_timenow() - parse_state
.link
->last_seen
> 1000 * 3600 * 24 * 7) {
2370 INFO("network_link_apply: discarding link signature " PRI_S_SRP
2371 ", prefix number %d, which is more than a week old", hexbuf
, parse_state
.link
->prefix_number
);
2372 RELEASE_HERE(parse_state
.link
, network_link_finalize
);
2376 parse_state
.link
->next
= network_links
;
2377 network_links
= parse_state
.link
;
2378 INFO("network_link_apply: parsed link signature " PRI_S_SRP
", prefix number %d", hexbuf
,
2379 network_links
->prefix_number
);
2380 // This is a temporary fix to clean up bogus link prefixes that may exist in preferences.
2381 if (network_links
->prefix_number
== 0) {
2382 network_links
->prefix_number
= ula_serial
++;
2384 if (network_links
->prefix_number
>= ula_serial
) {
2385 ula_serial
= network_links
->prefix_number
+ 1;
2391 network_link_record(network_link_t
*link
)
2394 CFDictionaryRef link_dictionary
;
2395 if (network_link_array
== NULL
) {
2396 ERROR("network_link_record: no network_link_array, can't record new link.");
2399 link_dictionary
= network_link_dictionary_copy(link
);
2400 if (link_dictionary
== NULL
) {
2401 ERROR("network_link_record: can't convert link into dictionary");
2404 CFArrayAppendValue(network_link_array
, link_dictionary
);
2406 CFPreferencesSetValue(CFSTR("network-links"), network_link_array
,
2407 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2408 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2409 if (!CFPreferencesSynchronize(CFSTR("com.apple.srp-mdns-proxy.preferences"),
2410 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
)) {
2411 ERROR("network_link_record: CFPreferencesSynchronize: Unable to store network link array.");
2413 CFRelease(link_dictionary
);
2414 dump_network_signature(hexbuf
, sizeof hexbuf
, link
->signature
, link
->signature_length
);
2415 INFO("network_link_record: recording link signature " PRI_S_SRP
", prefix number %d", hexbuf
, link
->prefix_number
);
2421 char ula_prefix_buffer
[INET6_ADDRSTRLEN
];
2422 struct in6_addr old_ula_prefix
;
2423 bool prefix_changed
;
2425 // Already have a prefix?
2426 if (ula_prefix
.s6_addr
[0] == 0xfd) {
2427 old_ula_prefix
= ula_prefix
;
2428 prefix_changed
= true;
2430 prefix_changed
= false;
2433 memset(&ula_prefix
, 0, sizeof(ula_prefix
));
2434 ula_prefix
.s6_addr
[0] = 0xfd;
2435 arc4random_buf(&ula_prefix
.s6_addr
[1], 5); // 40 bits of randomness
2437 inet_ntop(AF_INET6
, &ula_prefix
, ula_prefix_buffer
, sizeof ula_prefix_buffer
);
2438 CFStringRef ula_string
= CFStringCreateWithCString(NULL
, ula_prefix_buffer
, kCFStringEncodingUTF8
);
2439 if (ula_string
== NULL
) {
2440 ERROR("ula_generate: unable to create a ULA prefix string to store in preferences.");
2442 CFPreferencesSetValue(CFSTR("ula-prefix"), ula_string
,
2443 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2444 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2445 if (!CFPreferencesSynchronize(CFSTR("com.apple.srp-mdns-proxy.preferences"),
2446 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
)) {
2447 ERROR("CFPreferencesSynchronize: Unable to store ULA prefix.");
2449 CFRelease(ula_string
);
2451 if (prefix_changed
) {
2452 SEGMENTED_IPv6_ADDR_GEN_SRP(old_ula_prefix
.s6_addr
, old_prefix_buf
);
2453 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix
.s6_addr
, new_prefix_buf
);
2454 INFO("ula-generate: prefix changed from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
,
2455 SEGMENTED_IPv6_ADDR_PARAM_SRP(old_ula_prefix
.s6_addr
, old_prefix_buf
),
2456 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix
.s6_addr
, new_prefix_buf
));
2458 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix
.s6_addr
, new_prefix_buf
);
2459 INFO("ula-generate: generated ULA prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
2460 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix
.s6_addr
, new_prefix_buf
));
2463 // Set up the thread prefix.
2464 my_thread_prefix
= ula_prefix
;
2465 have_thread_prefix
= true;
2471 char ula_prefix_buffer
[INET6_ADDRSTRLEN
];
2472 bool have_stored_ula_prefix
= false;
2474 // Set up the ULA in case we need it.
2475 CFPropertyListRef plist
= CFPreferencesCopyValue(CFSTR("ula-prefix"),
2476 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2477 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2478 if (plist
!= NULL
) {
2479 if (CFGetTypeID(plist
) == CFStringGetTypeID()) {
2480 if (CFStringGetCString((CFStringRef
)plist
, ula_prefix_buffer
, sizeof(ula_prefix_buffer
),
2481 kCFStringEncodingUTF8
)) {
2482 if (inet_pton(AF_INET6
, ula_prefix_buffer
, &ula_prefix
)) {
2483 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix
.s6_addr
, ula_prefix_buf
);
2484 INFO("ula_setup: re-using stored prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
2485 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix
.s6_addr
, ula_prefix_buf
));
2486 have_stored_ula_prefix
= true;
2492 // Get the list of known network links (identified by network signature)
2493 plist
= CFPreferencesCopyValue(CFSTR("network-links"),
2494 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2495 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2497 if (plist
!= NULL
) {
2498 if (CFGetTypeID(plist
) == CFArrayGetTypeID()) {
2499 bool success
= true;
2500 CFArrayApplyFunction(plist
, CFRangeMake(0,CFArrayGetCount(plist
)), network_link_apply
, &success
);
2502 network_link_array
= CFArrayCreateMutableCopy(NULL
, 0, plist
);
2503 if (network_link_array
== NULL
) {
2504 ERROR("ula_setup: no memory for network link array!");
2512 // If we didn't get any links, make an empty array.
2513 if (network_link_array
== NULL
) {
2514 network_link_array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2515 if (network_link_array
== NULL
) {
2516 ERROR("ula_setup: unable to make network_link_array.");
2518 INFO("ula_setup: created empty network_link_array.");
2522 // If we didn't already successfully fetch a stored prefix, try to store one.
2523 if (!have_stored_ula_prefix
) {
2526 // Set up the thread prefix.
2527 my_thread_prefix
= ula_prefix
;
2528 have_thread_prefix
= true;
2533 get_network_signature(interface_t
*interface
)
2535 nwi_state_t network_state
;
2536 nwi_ifstate_t interface_state
;
2538 const uint8_t *signature
= NULL
;
2539 network_link_t
*link
= NULL
;
2542 network_state
= nwi_state_copy();
2543 if (network_state
!= NULL
) {
2544 interface_state
= nwi_state_get_ifstate(network_state
, interface
->name
);
2545 if (interface_state
!= NULL
) {
2546 signature
= nwi_ifstate_get_signature(interface_state
, AF_INET
, &length
);
2547 if (signature
!= NULL
) {
2548 dump_network_signature(hexbuf
, sizeof(hexbuf
), signature
, length
);
2549 INFO("get_network_signature: interface " PUB_S_SRP
" has ipv4 signature " PRI_S_SRP
,
2550 interface
->name
, hexbuf
);
2552 signature
= nwi_ifstate_get_signature(interface_state
, AF_INET6
, &length
);
2553 if (signature
!= NULL
) {
2554 dump_network_signature(hexbuf
, sizeof(hexbuf
), signature
, length
);
2555 INFO("get_network_signature: interface " PUB_S_SRP
" has ipv6 signature " PRI_S_SRP
,
2556 interface
->name
, hexbuf
);
2558 INFO("get_network_signature: no signature on " PUB_S_SRP
, interface
->name
);
2562 if (signature
== NULL
) {
2565 for (link
= network_links
; link
!= NULL
; link
= link
->next
) {
2566 if (link
->signature_length
== length
&& (length
== 0 || !memcmp(link
->signature
, signature
, length
))) {
2571 link
= network_link_create(signature
, length
);
2573 nwi_state_release(network_state
);
2575 ERROR("get_network_signature: nwi_state_copy() failed on " PUB_S_SRP
, interface
->name
);
2578 // If we didn't get a network signature, we're going to treat that as a signature. The previous call to
2579 // network_link_create() can have the same effect.
2581 link
= network_link_create(NULL
, 0);
2584 if (link
!= NULL
&& link
->prefix_number
== 0) {
2585 // Assign a prefix number to the link.
2586 link
->prefix_number
= ula_serial
++;
2587 link
->last_seen
= ioloop_timenow();
2589 // Save this link in memory.
2590 link
->next
= network_links
;
2591 network_links
= link
;
2593 // Save this link signature in the preferences.
2594 network_link_record(link
);
2596 if (interface
->link
!= link
) {
2597 #if defined(USE_IPCONFIGURATION_SERVICE)
2598 if (interface
->on_link_prefix_configured
) {
2599 interface_prefix_deconfigure(interface
);
2602 interface
->link
= link
;
2607 start_icmp_listener(void)
2609 int sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
2611 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
2614 struct icmp6_filter filter
;
2618 ERROR("Unable to listen for icmp messages: " PUB_S_SRP
, strerror(errno
));
2623 // Only accept router advertisements and router solicits.
2624 ICMP6_FILTER_SETBLOCKALL(&filter
);
2625 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
2626 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT
, &filter
);
2627 rv
= setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filter
, sizeof(filter
));
2629 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP
".", strerror(errno
));
2634 // We want a source address and interface index
2635 rv
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &true_flag
, sizeof(true_flag
));
2637 ERROR("Can't set IPV6_RECVPKTINFO: " PUB_S_SRP
".", strerror(errno
));
2642 // We need to be able to reject RAs arriving from off-link.
2643 rv
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &true_flag
, sizeof(true_flag
));
2645 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP
".", strerror(errno
));
2650 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
2651 // Prevent our router advertisements from updating our routing table.
2652 rv
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &false_flag
, sizeof(false_flag
));
2654 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP
".", strerror(errno
));
2660 icmp_listener
.io_state
= ioloop_file_descriptor_create(sock
, NULL
, NULL
);
2661 if (icmp_listener
.io_state
== NULL
) {
2662 ERROR("No memory for ICMP I/O structure.");
2667 // Beacon out a router advertisement every three minutes.
2668 icmp_listener
.unsolicited_interval
= 180 * 1000;
2669 ioloop_add_reader(icmp_listener
.io_state
, icmp_callback
);
2671 // At this point we need to have a ULA prefix.
2678 interface_router_solicit_finalize(void *context
)
2680 interface_t
*interface
= context
;
2681 interface
->router_solicit_wakeup
= NULL
;
2685 router_solicit_callback(void *context
)
2687 interface_t
*interface
= context
;
2688 if (interface
->is_thread
) {
2689 INFO("discontinuing router solicitations on thread interface " PUB_S_SRP
, interface
->name
);
2692 if (interface
->num_solicits_sent
>= 3) {
2693 INFO("Done sending router solicitations on " PUB_S_SRP
".", interface
->name
);
2696 INFO("sending router solicitation on " PUB_S_SRP
, interface
->name
);
2697 router_solicit_send(interface
);
2699 interface
->num_solicits_sent
++;
2700 ioloop_add_wake_event(interface
->router_solicit_wakeup
,
2701 interface
, router_solicit_callback
, interface_router_solicit_finalize
,
2702 RTR_SOLICITATION_INTERVAL
* 1000 + srp_random16() % 1024);
2706 start_router_solicit(interface_t
*interface
)
2708 if (interface
->router_solicit_wakeup
== NULL
) {
2709 interface
->router_solicit_wakeup
= ioloop_wakeup_create();
2710 if (interface
->router_solicit_wakeup
== 0) {
2711 ERROR("No memory for router solicit wakeup on " PUB_S_SRP
".", interface
->name
);
2715 ioloop_cancel_wake_event(interface
->router_solicit_wakeup
);
2717 interface
->num_solicits_sent
= 0;
2718 ioloop_add_wake_event(interface
->router_solicit_wakeup
, interface
, router_solicit_callback
,
2719 interface_router_solicit_finalize
, 128 + srp_random16() % 896);
2723 icmp_interface_subscribe(interface_t
*interface
, bool added
)
2725 struct ipv6_mreq req
;
2728 if (icmp_listener
.io_state
== NULL
) {
2729 ERROR("Interface subscribe without ICMP listener.");
2733 memset(&req
, 0, sizeof req
);
2734 if (interface
->index
== -1) {
2735 ERROR("icmp_interface_subscribe called before interface index fetch for " PUB_S_SRP
, interface
->name
);
2739 req
.ipv6mr_multiaddr
= in6addr_linklocal_allrouters
;
2740 req
.ipv6mr_interface
= interface
->index
;
2741 rv
= setsockopt(icmp_listener
.io_state
->fd
, IPPROTO_IPV6
, added
? IPV6_JOIN_GROUP
: IPV6_LEAVE_GROUP
, &req
,
2744 ERROR("Unable to " PUB_S_SRP
" all-routers multicast group on " PUB_S_SRP
": " PUB_S_SRP
,
2745 added
? "join" : "leave", interface
->name
, strerror(errno
));
2748 INFO("icmp_interface_subscribe: " PUB_S_SRP
"subscribed on interface " PUB_S_SRP
, added
? "" : "un",
2753 static interface_t
*
2754 find_interface(const char *name
, int ifindex
)
2756 interface_t
**p_interface
, *interface
= NULL
;
2758 for (p_interface
= &interfaces
; *p_interface
; p_interface
= &(*p_interface
)->next
) {
2759 interface
= *p_interface
;
2760 if (!strcmp(name
, interface
->name
)) {
2761 if (ifindex
!= -1 && interface
->index
!= ifindex
) {
2762 INFO("interface name " PUB_S_SRP
" index changed from %d to %d", name
, interface
->index
, ifindex
);
2763 interface
->index
= ifindex
;
2769 // If it's a new interface, make a structure.
2770 // We could do a callback, but don't have a use case
2771 if (*p_interface
== NULL
) {
2772 interface
= interface_create(name
, ifindex
);
2773 *p_interface
= interface
;
2778 NW_EXPORT_PROJECT NW_RETURNS_RETAINED nw_path_evaluator_t
2779 nw_path_create_evaluator_for_listener(nw_parameters_t parameters
,
2783 interface_shutdown(interface_t
*interface
)
2785 icmp_message_t
*router
, *next
;
2786 INFO("Interface " PUB_S_SRP
" went away.", interface
->name
);
2787 if (interface
->beacon_wakeup
!= NULL
) {
2788 ioloop_cancel_wake_event(interface
->beacon_wakeup
);
2790 if (interface
->post_solicit_wakeup
!= NULL
) {
2791 ioloop_cancel_wake_event(interface
->post_solicit_wakeup
);
2793 if (interface
->router_solicit_wakeup
!= NULL
) {
2794 ioloop_cancel_wake_event(interface
->router_solicit_wakeup
);
2796 if (interface
->deconfigure_wakeup
!= NULL
) {
2797 ioloop_cancel_wake_event(interface
->deconfigure_wakeup
);
2799 if (interface
->vicarious_discovery_complete
!= NULL
) {
2800 ioloop_cancel_wake_event(interface
->vicarious_discovery_complete
);
2802 for (router
= interface
->routers
; router
; router
= next
) {
2803 next
= router
->next
;
2804 icmp_message_free(router
);
2806 interface
->routers
= NULL
;
2807 if (interface
->ip_configuration_service
!= NULL
) {
2808 CFRelease(interface
->ip_configuration_service
);
2809 interface
->ip_configuration_service
= NULL
;
2811 interface
->last_beacon
= interface
->next_beacon
= 0;
2812 interface
->deprecate_deadline
= 0;
2813 interface
->preferred_lifetime
= interface
->valid_lifetime
= 0;
2814 interface
->num_solicits_sent
= 0;
2815 interface
->inactive
= true;
2816 interface
->ineligible
= true;
2817 interface
->advertise_ipv6_prefix
= false;
2818 interface
->have_link_layer_address
= false;
2819 interface
->on_link_prefix_configured
= false;
2820 interface
->sent_first_beacon
= false;
2821 interface
->num_beacons_sent
= 0;
2822 interface
->router_discovery_complete
= false;
2823 interface
->router_discovery_in_progress
= false;
2824 interface
->vicarious_router_discovery_in_progress
= false;
2825 interface
->need_reconfigure_prefix
= false;
2826 interface
->link
= NULL
;
2830 interface_prefix_evaluate(interface_t
*interface
)
2834 // We are assuming here that the network signature can't change without us seeing a state transition.
2835 // Cases where this assumption could be violated include unplugging a WiFi base station configured as
2836 // a bridge from one ethernet network and plugging it into a different one. We could trigger a
2837 // re-evaluation when an IPv4 address on an interface changes, and also when there had been a prefix
2838 // advertised and no longer is.
2839 get_network_signature(interface
);
2841 // This should only happen if we're really low on memory.
2842 if (interface
->link
== NULL
) {
2843 INFO("interface_prefix_evaluate: newly active interface " PUB_S_SRP
" has no link.", interface
->name
);
2846 if (interface
->link
->primary
!= NULL
&&
2847 (interface
->link
->primary
->inactive
|| interface
->link
->primary
->ineligible
))
2849 INFO("Removing primary interface " PUB_S_SRP
" from link because it's inactive or ineligible.",
2850 interface
->link
->primary
->name
);
2851 interface
->link
->primary
= NULL
;
2854 if (interface
->link
->primary
== NULL
) {
2855 // Make this interface primary for the link.
2856 interface
->link
->primary
= interface
;
2858 // Set up the interface prefix using the prefix number for the link.
2859 interface
->ipv6_prefix
= ula_prefix
;
2860 interface
->ipv6_prefix
.s6_addr
[6] = interface
->link
->prefix_number
>> 8;
2861 interface
->ipv6_prefix
.s6_addr
[7] = interface
->link
->prefix_number
& 255;
2863 dump_network_signature(hexbuf
, sizeof(hexbuf
), interface
->link
->signature
,
2864 interface
->link
->signature_length
);
2865 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
);
2866 INFO("Interface " PUB_S_SRP
" is now primary for network " PRI_S_SRP
" with prefix "
2867 PRI_SEGMENTED_IPv6_ADDR_SRP
, interface
->name
, hexbuf
,
2868 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
));
2870 if (interface
->link
->primary
!= interface
) {
2871 INFO("interface_prefix_evaluate: not setting up " PUB_S_SRP
" because interface " PUB_S_SRP
2872 " is primary for the link.", interface
->name
, interface
->link
->primary
->name
);
2879 interface_active_state_evaluate(interface_t
*interface
, bool active_known
, bool active
)
2881 INFO("interface_active_state_evaluate: evaluating interface active status - ifname: " PUB_S_SRP
2882 ", active_known: " PUB_S_SRP
", active: " PUB_S_SRP
", inactive: " PUB_S_SRP
,
2883 interface
->name
, active_known
? "true" : "false", active
? "true" : "false",
2884 interface
->inactive
? "true" : "false");
2886 if (active_known
&& !active
) {
2887 if (!interface
->inactive
) {
2888 // If we are the primary interface for the link to which we were connected, see if there's
2889 // another interface on the link and in any case make this interface not primary for that
2891 if (interface
->link
!= NULL
&& interface
->link
->primary
== interface
) {
2893 interface
->link
->primary
= NULL
;
2894 for (scan
= interfaces
; scan
; scan
= scan
->next
) {
2895 if (scan
!= interface
&& scan
->link
== interface
->link
&& !scan
->inactive
&& !scan
->ineligible
) {
2896 // Set up the thread-local prefix
2897 interface_prefix_evaluate(scan
);
2899 // We need to reevaluate routing policy on the new primary interface now, because
2900 // there may be no new event there to trigger one.
2901 routing_policy_evaluate(scan
, true);
2908 icmp_interface_subscribe(interface
, false);
2909 interface_shutdown(interface
);
2911 // Zero IPv4 addresses.
2912 interface
->num_ipv4_addresses
= 0;
2914 INFO("interface_active_state_evaluate: interface went down - ifname: " PUB_S_SRP
, interface
->name
);
2916 } else if (active_known
) {
2917 if (interface
->inactive
) {
2918 INFO("interface_active_state_evaluate: interface " PUB_S_SRP
" showed up.", interface
->name
);
2920 if (!strcmp(interface
->name
, thread_interface_name
) || !strcmp(interface
->name
, home_interface_name
)) {
2922 // Zero IPv4 addresses.
2923 interface
->num_ipv4_addresses
= 0;
2925 icmp_interface_subscribe(interface
, true);
2926 interface
->inactive
= false;
2928 interface_prefix_evaluate(interface
);
2930 if (partition_can_provide_routing
) {
2932 router_discovery_start(interface
);
2934 // If we already have a thread prefix, trigger beaconing now.
2935 if (published_thread_prefix
!= NULL
|| adopted_thread_prefix
!= NULL
) {
2936 interface_beacon_schedule(interface
, 0);
2938 INFO("No prefix on thread network, so not scheduling beacon.");
2942 INFO("Can't provide routing, so not scheduling beacon.");
2947 INFO("interface_active_state_evaluate: skipping interface " PUB_S_SRP
2948 " because it's not home or thread.", interface
->name
);
2956 nw_interface_state_changed(nw_interface_t iface
, int sock
, const char *name
, bool ineligible
)
2958 int ifindex
= nw_interface_get_index(iface
);
2960 bool active_known
= false;
2961 interface_t
*interface
;
2962 struct ifmediareq media_request
;
2964 interface
= find_interface(name
, ifindex
);
2965 if (interface
== NULL
) {
2972 if (interface
->ineligible
) {
2973 INFO("nw_interface_state_changed: interface " PUB_S_SRP
" is eligible to be used for routing.", name
);
2975 interface
->ineligible
= false;
2977 INFO("nw_interface_state_changed: interface " PUB_S_SRP
" index %d: " PUB_S_SRP
", " PUB_S_SRP
")",
2978 name
, ifindex
, (active_known
? (active
? "active" : "inactive") : "unknown"),
2979 ineligible
? "ineligible" : "eligible");
2982 memset(&media_request
, 0, sizeof(media_request
));
2983 strlcpy(media_request
.ifm_name
, name
, sizeof(media_request
.ifm_name
));
2984 if (ioctl(sock
, SIOCGIFXMEDIA
, (caddr_t
)&media_request
) >= 0) {
2985 if (media_request
.ifm_status
& IFM_ACTIVE
) {
2987 active_known
= true;
2990 active_known
= true;
2995 active_known
= false;
2998 if (interface
->index
== -1) {
2999 interface
->index
= ifindex
;
3001 interface_active_state_evaluate(interface
, active_known
, active
);
3005 ifaddr_callback(void *__unused context
, const char *name
, const addr_t
*address
, const addr_t
*mask
,
3006 unsigned flags
, enum interface_address_change change
)
3008 char addrbuf
[INET6_ADDRSTRLEN
];
3009 const uint8_t *addrbytes
, *maskbytes
, *prefp
;
3011 interface_t
*interface
;
3012 bool is_thread_interface
= false;
3014 interface
= find_interface(name
, -1);
3015 if (interface
== NULL
) {
3016 ERROR("ifaddr_callback: find_interface returned NULL for " PUB_S_SRP
, name
);
3020 if (thread_interface_name
!= NULL
&& !strcmp(name
, thread_interface_name
)) {
3021 is_thread_interface
= true;
3024 if (address
->sa
.sa_family
== AF_INET
) {
3025 addrbytes
= (uint8_t *)&address
->sin
.sin_addr
;
3026 maskbytes
= (uint8_t *)&mask
->sin
.sin_addr
;
3027 prefp
= maskbytes
+ 3;
3029 if (change
== interface_address_added
) {
3030 // Just got an IPv4 address?
3031 if (!interface
->num_ipv4_addresses
) {
3032 interface_prefix_evaluate(interface
);
3034 interface
->num_ipv4_addresses
++;
3035 } else if (change
== interface_address_deleted
) {
3036 interface
->num_ipv4_addresses
--;
3037 // Just lost our last IPv4 address?
3038 if (!interface
->num_ipv4_addresses
) {
3039 interface_prefix_evaluate(interface
);
3042 } else if (address
->sa
.sa_family
== AF_INET6
) {
3043 addrbytes
= (uint8_t *)&address
->sin6
.sin6_addr
;
3044 maskbytes
= (uint8_t *)&mask
->sin6
.sin6_addr
;
3045 prefp
= maskbytes
+ 15;
3047 } else if (address
->sa
.sa_family
== AF_LINK
) {
3048 snprintf(addrbuf
, sizeof addrbuf
, "%02x:%02x:%02x:%02x:%02x:%02x",
3049 address
->ether_addr
.addr
[0], address
->ether_addr
.addr
[1],
3050 address
->ether_addr
.addr
[2], address
->ether_addr
.addr
[3],
3051 address
->ether_addr
.addr
[4], address
->ether_addr
.addr
[5]);
3052 prefp
= (uint8_t *)&addrbuf
[0]; maskbytes
= prefp
+ 1; // Skip prefix length calculation
3056 INFO("ifaddr_callback: Unknown address type %d", address
->sa
.sa_family
);
3060 if (change
!= interface_address_unchanged
) {
3061 if (address
->sa
.sa_family
== AF_LINK
) {
3062 if (!interface
->ineligible
) {
3063 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP
" " PUB_S_SRP
" " PRI_MAC_ADDR_SRP
" flags %x",
3064 name
, is_thread_interface
? " (thread)" : "",
3065 change
== interface_address_added
? "added" : "removed",
3066 MAC_ADDR_PARAM_SRP(address
->ether_addr
.addr
), flags
);
3069 for (; prefp
>= maskbytes
; prefp
--) {
3075 for (i
= 0; i
< 8; i
++) {
3076 if (*prefp
& (1<<i
)) {
3081 inet_ntop(address
->sa
.sa_family
, addrbytes
, addrbuf
, sizeof addrbuf
);
3082 if (!interface
->ineligible
) {
3083 if (address
->sa
.sa_family
== AF_INET
) {
3084 IPv4_ADDR_GEN_SRP(addrbytes
, addr_buf
);
3085 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP
" " PUB_S_SRP
" " PRI_IPv4_ADDR_SRP
3086 "/%d flags %x", name
, is_thread_interface
? " (thread)" : "",
3087 change
== interface_address_added
? "added" : "removed",
3088 IPv4_ADDR_PARAM_SRP(addrbytes
, addr_buf
), preflen
, flags
);
3089 } else if (address
->sa
.sa_family
== AF_INET6
) {
3090 SEGMENTED_IPv6_ADDR_GEN_SRP(addrbytes
, addr_buf
);
3091 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP
" " PUB_S_SRP
" " PRI_SEGMENTED_IPv6_ADDR_SRP
3092 "/%d flags %x", name
, is_thread_interface
? " (thread)" : "",
3093 change
== interface_address_added
? "added" : "removed",
3094 SEGMENTED_IPv6_ADDR_PARAM_SRP(addrbytes
, addr_buf
), preflen
, flags
);
3096 INFO("ifaddr_callback - invalid sa_family: %d", address
->sa
.sa_family
);
3099 // When new IP address is removed, it is possible that the existing router information, such as
3100 // PIO and RIO is no longer valid since srp-mdns-proxy is losing its IP address. In order to let it to
3101 // flush the stale router information as soon as possible, we mark all the router as stale immediately,
3102 // by setting the router received time to a value which is 601s ago (router will be stale if the router
3103 // information is received for more than 600s). And then do router discovery for 20s, so we can ensure
3104 // that all the stale router information will be updated during the discovery, or flushed away. If all
3105 // routers are flushed, then srp-mdns-proxy will advertise its own prefix and configure the new IPv6
3107 if ((address
->sa
.sa_family
== AF_INET
|| address
->sa
.sa_family
== AF_INET6
) &&
3108 change
== interface_address_deleted
) {
3109 INFO("ifaddr_callback: making all routers stale and start router discovery due to removed address");
3110 adjust_router_received_time(interface
, ioloop_timenow(),
3111 -(MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE
+ MSEC_PER_SEC
));
3112 // Explicitly set router_discovery_complete to false so we can ensure that srp-mdns-proxy will start
3113 // the router discovery immediately.
3114 interface
->router_discovery_complete
= false;
3115 // Set need_reconfigure_prefix to true to let routing_policy_evaluate know that the router discovery
3116 // is caused by interface removal event, so when the router discovery finished and nothing changes,
3117 // it can reconfigure the IPv6 routing in case configured does not handle it correctly.
3118 interface
->need_reconfigure_prefix
= true;
3119 routing_policy_evaluate(interface
, false);
3125 // Not a broadcast interface
3126 if (flags
& (IFF_LOOPBACK
| IFF_POINTOPOINT
)) {
3127 // Not the thread interface
3128 if (!is_thread_interface
) {
3134 if (address
->sa
.sa_family
== AF_INET
&& IN_LINKLOCAL(address
->sin
.sin_addr
.s_addr
)) {
3138 if (interface
->index
== -1) {
3139 interface
->index
= address
->ether_addr
.index
;
3141 interface
->is_thread
= is_thread_interface
;
3143 #if TARGET_OS_TV && !defined(RA_TESTER)
3144 if (is_thread_interface
&& address
->sa
.sa_family
== AF_INET6
) {
3145 partition_utun0_address_changed(&address
->sin6
.sin6_addr
, change
);
3149 if (address
->sa
.sa_family
== AF_INET
) {
3150 } else if (address
->sa
.sa_family
== AF_INET6
) {
3151 if (IN6_IS_ADDR_LINKLOCAL(&address
->sin6
.sin6_addr
)) {
3152 interface
->link_local
= address
->sin6
.sin6_addr
;
3154 } else if (address
->sa
.sa_family
== AF_LINK
) {
3155 if (address
->ether_addr
.len
== 6) {
3156 memcpy(interface
->link_layer
, address
->ether_addr
.addr
, 6);
3157 interface
->have_link_layer_address
= true;
3163 refresh_interface_list(void)
3165 ioloop_map_interface_addresses(NULL
, ifaddr_callback
);
3169 nw_path_event(nw_path_t path
)
3171 int sock
= socket(PF_INET6
, SOCK_DGRAM
, 0);
3172 INFO("nw_path_event");
3173 nw_path_enumerate_interfaces(path
, ^bool (nw_interface_t NONNULL iface
) {
3174 const char *name
= nw_interface_get_name(iface
);
3175 CFStringRef sc_name
= CFStringCreateWithCStringNoCopy(NULL
, name
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
3176 if (sc_name
!= NULL
) {
3177 SCNetworkInterfaceRef
_SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator
,
3178 CFStringRef bsdName
, UInt32 flags
);
3179 SCNetworkInterfaceRef sc_interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, sc_name
, 0);
3181 if (sc_interface
== NULL
) {
3182 ERROR("SCNetworkInterfaceCreateWithBSDName failed");
3183 nw_interface_state_changed(iface
, sock
, name
, true);
3186 CFStringRef sc_type
= SCNetworkInterfaceGetInterfaceType(sc_interface
);
3187 if (sc_type
== NULL
) {
3188 ERROR("Unable to get interface type on " PUB_S_SRP
, name
);
3189 CFRelease(sc_interface
);
3192 CFStringRef
_SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface
);
3193 CFStringRef io_path
= _SCNetworkInterfaceGetIOPath(sc_interface
);
3194 bool is_usb
= false;
3195 if (io_path
== NULL
) {
3196 if (strncmp(name
, "utun", 4)) {
3197 ERROR("Unable to get interface I/O path.");
3200 #ifdef DEBUG_VERBOSE
3201 char pathname
[1024];
3202 CFStringGetCString(io_path
, pathname
, sizeof(pathname
), kCFStringEncodingUTF8
);
3203 INFO("Interface " PUB_S_SRP
" I/O Path: " PRI_S_SRP
, name
, pathname
);
3205 CFRange match
= CFStringFind(io_path
, CFSTR("AppleUSBDeviceNCMData"), 0);
3206 if (match
.location
!= kCFNotFound
) {
3210 if (CFEqual(sc_type
, kSCNetworkInterfaceTypeIEEE80211
) ||
3211 (CFEqual(sc_type
, kSCNetworkInterfaceTypeEthernet
) && !is_usb
))
3213 nw_interface_state_changed(iface
, sock
, name
, false);
3215 nw_interface_state_changed(iface
, sock
, name
, true);
3217 CFRelease(sc_interface
);
3222 nw_interface_state_changed(iface
, sock
, name
, true);
3228 #if TARGET_OS_TV && !defined(RA_TESTER)
3229 // If we do not have an active interface, we can't be advertising SRP service.
3230 interface_t
*interface
;
3231 bool active
= false;
3232 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
3233 if (!interface
->ineligible
&& !interface
->inactive
) {
3237 if (active
&& !have_non_thread_interface
) {
3238 INFO("nw_path_event: we have an active interface");
3239 have_non_thread_interface
= true;
3240 partition_can_advertise_service
= true;
3241 } else if (!active
&& have_non_thread_interface
) {
3242 INFO("nw_path_event: we no longer have an active interface");
3243 have_non_thread_interface
= false;
3244 // Stop advertising the service, if we are doing so.
3245 partition_discontinue_srp_service();
3247 #endif // TARGET_OS_TV && !defined(RA_TESTER)
3249 refresh_interface_list();
3252 #if TARGET_OS_TV && !defined(RA_TESTER)
3253 #ifdef GET_TUNNEL_NAME_WITH_WPANCTL
3255 thread_interface_output(io_t
*io
, void *__unused context
)
3261 // We are assuming that wpanctl will never do partial-line writes.
3262 rv
= read(io
->fd
, inbuf
, sizeof(inbuf
) - 1);
3264 ERROR("thread_interface_output: " PUB_S_SRP
, strerror(errno
));
3266 INFO("read %" PRIs64
" bytes from wpanctl output", rv
);
3268 INFO("Done with thread interface output.");
3271 if (inbuf
[rv
- 1] == '\n') {
3273 s
= strchr(inbuf
, '>');
3276 ERROR("Bad wpanctl output: " PUB_S_SRP
, inbuf
);
3283 // We don't expect the end of string here.
3288 if (s
== t
|| t
== NULL
) {
3292 if (num_thread_interfaces
!= 0) {
3293 INFO("Already have a thread interface.");
3295 num_thread_interfaces
= 1;
3296 thread_interface_name
= strdup(s
);
3297 if (thread_interface_name
== NULL
) {
3298 ERROR("No memory to save thread interface name " PUB_S_SRP
, s
);
3301 INFO("Thread interface at " PUB_S_SRP
, thread_interface_name
);
3302 partition_got_tunnel_name();
3311 thread_interface_done(void *__unused context
, int status
, const char *error
)
3313 if (error
!= NULL
) {
3314 ERROR("thread_interface_done: " PUB_S_SRP
, error
);
3316 INFO("thread_interface_done: %d.", status
);
3318 ioloop_subproc_release(thread_interface_enumerator_process
);
3320 #endif // GET_TUNNEL_NAME_WITH_WPANCTL
3323 cti_get_tunnel_name_callback(void *__unused context
, const char *name
, cti_status_t status
)
3325 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3326 INFO("cti_get_tunnel_name_callback: disconnected");
3327 adv_xpc_disconnect();
3331 INFO("cti_get_tunnel_name_callback: " PUB_S_SRP
" %d", name
!= NULL
? name
: "<null>", status
);
3332 if (status
!= kCTIStatus_NoError
) {
3335 num_thread_interfaces
= 1;
3336 if (thread_interface_name
!= NULL
) {
3337 free(thread_interface_name
);
3339 thread_interface_name
= strdup(name
);
3340 if (thread_interface_name
== NULL
) {
3341 ERROR("No memory to save thread interface name " PUB_S_SRP
, name
);
3344 INFO("Thread interface at " PUB_S_SRP
, thread_interface_name
);
3345 partition_got_tunnel_name();
3349 cti_get_role_callback(void *__unused context
, cti_network_node_type_t role
, cti_status_t status
)
3351 bool am_thread_router
= false;
3353 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3354 INFO("cti_get_role_callback: disconnected");
3355 adv_xpc_disconnect();
3359 partition_last_role_change
= ioloop_timenow();
3361 if (status
== kCTIStatus_NoError
) {
3362 if (role
== kCTI_NetworkNodeType_Router
|| role
== kCTI_NetworkNodeType_Leader
) {
3363 am_thread_router
= true;
3366 INFO("role is: " PUB_S_SRP
" (%d)\n ", am_thread_router
? "router" : "not router", role
);
3368 ERROR("cti_get_role_callback: nonzero status %d", status
);
3371 // Our thread role doesn't actually matter, but it's useful to report it in the logs.
3375 cti_get_state_callback(void *__unused context
, cti_network_state_t state
, cti_status_t status
)
3377 bool associated
= false;
3379 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3380 INFO("cti_get_state_callback: disconnected");
3381 adv_xpc_disconnect();
3385 partition_last_state_change
= ioloop_timenow();
3387 if (status
== kCTIStatus_NoError
) {
3388 if ((state
== kCTI_NCPState_Associated
) || (state
== kCTI_NCPState_Isolated
) ||
3389 (state
== kCTI_NCPState_NetWake_Asleep
) || (state
== kCTI_NCPState_NetWake_Waking
))
3394 INFO("state is: " PUB_S_SRP
" (%d)\n ", associated
? "associated" : "not associated", state
);
3396 ERROR("cti_get_state_callback: nonzero status %d", status
);
3399 if (current_thread_state
!= state
) {
3401 current_thread_state
= state
;
3402 partition_maybe_enable_services(); // but probably not
3404 current_thread_state
= state
;
3405 partition_disable_service();
3411 cti_get_partition_id_callback(void *__unused context
, int32_t partition_id
, cti_status_t status
)
3413 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3414 INFO("cti_get_partition_id_callback: disconnected");
3415 adv_xpc_disconnect();
3419 if (status
== kCTIStatus_NoError
) {
3420 INFO("Partition ID changed to %" PRIu32
, partition_id
);
3421 thread_partition_id
[0] = (uint8_t)((partition_id
>> 24) & 255);
3422 thread_partition_id
[1] = (uint8_t)((partition_id
>> 16) & 255);
3423 thread_partition_id
[2] = (uint8_t)((partition_id
>> 8) & 255);
3424 thread_partition_id
[3] = (uint8_t)(partition_id
& 255);
3426 partition_id_changed();
3428 ERROR("cti_get_state_callback: nonzero status %d", status
);
3433 thread_service_note(thread_service_t
*service
, const char *event_description
)
3437 port
= (service
->port
[0] << 8) | service
->port
[1];
3438 SEGMENTED_IPv6_ADDR_GEN_SRP(service
->address
, service_add_buf
);
3439 INFO("SRP service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d " PUB_S_SRP
,
3440 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, service_add_buf
),
3441 port
, event_description
);
3445 thread_pref_id_note(thread_pref_id_t
*pref_id
, const char *event_description
)
3447 struct in6_addr addr
;
3449 addr
.s6_addr
[0] = 0xfd;
3450 memcpy(&addr
.s6_addr
[1], pref_id
->prefix
, 5);
3451 memset(&addr
.s6_addr
[6], 0, 10);
3452 SEGMENTED_IPv6_ADDR_GEN_SRP(addr
.s6_addr
, addr_buf
);
3453 INFO("pref:id " PRI_SEGMENTED_IPv6_ADDR_SRP
":%02x%02x%02x%02x " PUB_S_SRP
,
3454 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
.s6_addr
, addr_buf
),
3455 pref_id
->partition_id
[0], pref_id
->partition_id
[1], pref_id
->partition_id
[2], pref_id
->partition_id
[3],
3459 typedef struct state_debug_accumulator
{
3460 char change
[20]; // " +stable +user +ncp"
3467 accumulator_init(accumulator_t
*accumulator
)
3469 memset(accumulator
, 0, sizeof(*accumulator
));
3470 accumulator
->p_change
= accumulator
->change
;
3471 accumulator
->left
= sizeof(accumulator
->change
);
3475 accumulate(accumulator_t
*accumulator
, bool previous
, bool cur
, const char *name
)
3478 if (previous
!= cur
) {
3479 snprintf(accumulator
->p_change
, accumulator
->left
, "%s%s%s",
3480 accumulator
->p_change
== accumulator
->change
? "" : " ", cur
? "+" : "-", name
);
3481 len
= strlen(accumulator
->p_change
);
3482 accumulator
->p_change
+= len
;
3483 accumulator
->left
-= len
;
3484 accumulator
->changed
= true;
3489 cti_service_list_callback(void *__unused context
, cti_service_vec_t
*services
, cti_status_t status
)
3492 thread_service_t
**pservice
= &thread_services
, *service
= NULL
;
3493 thread_pref_id_t
**ppref_id
= &thread_pref_ids
, *pref_id
= NULL
;
3495 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3496 INFO("cti_get_service_list_callback: disconnected");
3497 adv_xpc_disconnect();
3501 if (status
!= kCTIStatus_NoError
) {
3502 ERROR("cti_get_service_list_callback: %d", status
);
3504 // Delete any SRP services that are not in the list provided by Thread.
3505 while (*pservice
!= NULL
) {
3506 service
= *pservice
;
3507 for (i
= 0; i
< services
->num
; i
++) {
3508 cti_service_t
*cti_service
= services
->services
[i
];
3509 // Is this a valid SRP service?
3510 if (IS_SRP_SERVICE(cti_service
)) {
3511 // Is this service still present?
3512 if (!memcmp(&service
->address
, cti_service
->server
, 16) &&
3513 !memcmp(&service
->port
, &cti_service
->server
[16], 2)) {
3518 if (i
== services
->num
) {
3519 thread_service_note(service
, "went away");
3520 *pservice
= service
->next
;
3521 RELEASE_HERE(service
, thread_service_finalize
);
3523 // We'll re-initialize these flags from the service list when we check for duplicates.
3524 service
->previous_user
= service
->user
;
3525 service
->user
= false;
3526 service
->previous_stable
= service
->stable
;
3527 service
->stable
= false;
3528 service
->previous_ncp
= service
->ncp
;
3529 service
->ncp
= false;
3530 pservice
= &service
->next
;
3533 // On exit, pservice is pointing to the end-of-list pointer.
3535 // Delete any pref_id services that are not in the list provided by Thread.
3536 while (*ppref_id
!= NULL
) {
3537 pref_id
= *ppref_id
;
3538 for (i
= 0; i
< services
->num
; i
++) {
3539 cti_service_t
*cti_service
= services
->services
[i
];
3540 // Is this an SRP service?
3541 if (IS_PREF_ID_SERVICE(cti_service
)) {
3542 // Is this service still present?
3543 if (!memcmp(&pref_id
->partition_id
, cti_service
->server
, 4) &&
3544 !memcmp(pref_id
->prefix
, &cti_service
->server
[4], 5))
3550 if (i
== services
->num
) {
3551 thread_pref_id_note(pref_id
, "went away");
3552 *ppref_id
= pref_id
->next
;
3553 RELEASE_HERE(pref_id
, thread_pref_id_finalize
);
3555 // We'll re-initialize these flags from the service list when we check for duplicates.
3556 pref_id
->previous_user
= pref_id
->user
;
3557 pref_id
->user
= false;
3558 pref_id
->previous_stable
= pref_id
->stable
;
3559 pref_id
->stable
= false;
3560 pref_id
->previous_ncp
= pref_id
->ncp
;
3561 pref_id
->ncp
= false;
3562 ppref_id
= &pref_id
->next
;
3565 // On exit, pservice is pointing to the end-of-list pointer.
3567 // Add any services that are not present.
3568 for (i
= 0; i
< services
->num
; i
++) {
3569 cti_service_t
*cti_service
= services
->services
[i
];
3570 if (IS_SRP_SERVICE(cti_service
)) {
3571 for (service
= thread_services
; service
!= NULL
; service
= service
->next
) {
3572 if (!memcmp(&service
->address
, cti_service
->server
, 16) &&
3573 !memcmp(&service
->port
, &cti_service
->server
[16], 2)) {
3577 if (service
== NULL
) {
3578 service
= thread_service_create(cti_service
->server
, &cti_service
->server
[16]);
3579 if (service
== NULL
) {
3580 ERROR("cti_service_list_callback: no memory for service.");
3582 thread_service_note(service
, "showed up");
3583 *pservice
= service
;
3584 pservice
= &service
->next
;
3587 // Also, since we're combing the list, update ncp, user and stable flags. Note that a service can
3588 // appear more than once in the thread service list.
3589 if (service
!= NULL
) {
3590 if (cti_service
->flags
& kCTIFlag_NCP
) {
3591 service
->ncp
= true;
3593 service
->user
= true;
3595 if (cti_service
->flags
& kCTIFlag_Stable
) {
3596 service
->stable
= true;
3599 } else if (IS_PREF_ID_SERVICE(cti_service
)) {
3600 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= pref_id
->next
) {
3601 if (!memcmp(&pref_id
->partition_id
, cti_service
->server
, 4) &&
3602 !memcmp(pref_id
->prefix
, &cti_service
->server
[4], 5))
3607 if (pref_id
== NULL
) {
3608 pref_id
= thread_pref_id_create(cti_service
->server
, &cti_service
->server
[4]);
3609 if (pref_id
== NULL
) {
3610 ERROR("cti_service_list_callback: no memory for pref_id.");
3612 thread_pref_id_note(pref_id
, "showed up");
3613 *ppref_id
= pref_id
;
3614 ppref_id
= &pref_id
->next
;
3617 // Also, since we're combing the list, update ncp, user and stable flags. Note that a pref_id can
3618 // appear more than once in the thread pref_id list.
3619 if (pref_id
!= NULL
) {
3620 if (!pref_id
->ncp
&& (cti_service
->flags
& kCTIFlag_NCP
)) {
3621 pref_id
->ncp
= true;
3622 } else if (!pref_id
->user
&& !(cti_service
->flags
& kCTIFlag_NCP
)) {
3623 pref_id
->user
= true;
3625 if (cti_service
->flags
& kCTIFlag_Stable
) {
3626 pref_id
->stable
= true;
3632 accumulator_t accumulator
;
3633 for (service
= thread_services
; service
!= NULL
; service
= service
->next
) {
3634 accumulator_init(&accumulator
);
3635 accumulate(&accumulator
, service
->previous_ncp
, service
->ncp
, "ncp");
3636 accumulate(&accumulator
, service
->previous_stable
, service
->ncp
, "stable");
3637 accumulate(&accumulator
, service
->previous_user
, service
->user
, "user");
3638 if (accumulator
.changed
) {
3639 thread_service_note(service
, accumulator
.change
);
3642 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= pref_id
->next
) {
3643 accumulator_init(&accumulator
);
3644 accumulate(&accumulator
, pref_id
->previous_ncp
, pref_id
->ncp
, "ncp");
3645 accumulate(&accumulator
, pref_id
->previous_stable
, pref_id
->ncp
, "stable");
3646 accumulate(&accumulator
, pref_id
->previous_user
, pref_id
->user
, "user");
3647 if (accumulator
.changed
) {
3648 thread_pref_id_note(pref_id
, accumulator
.change
);
3652 // At this point the thread prefix list contains the same information as what we just received.
3653 // Trigger a "prefix set changed" event.
3654 partition_service_set_changed();
3659 cti_prefix_list_callback(void *__unused context
, cti_prefix_vec_t
*prefixes
, cti_status_t status
)
3662 thread_prefix_t
**ppref
= &thread_prefixes
, *prefix
= NULL
;
3664 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3665 INFO("cti_get_prefix_list_callback: disconnected");
3666 adv_xpc_disconnect();
3670 if (status
!= kCTIStatus_NoError
) {
3671 ERROR("cti_get_prefix_list_callback: %d", status
);
3673 // Delete any prefixes that are not in the list provided by Thread.
3674 while (*ppref
!= NULL
) {
3676 for (i
= 0; i
< prefixes
->num
; i
++) {
3677 cti_prefix_t
*cti_prefix
= prefixes
->prefixes
[i
];
3678 // Is this prefix still present?
3679 if (!memcmp(&prefix
->prefix
, &cti_prefix
->prefix
, 8)) {
3683 if (i
== prefixes
->num
) {
3684 *ppref
= prefix
->next
;
3685 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, prefix_buf
);
3686 INFO("cti_prefix_list_callback: prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" went away",
3687 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, prefix_buf
));
3688 RELEASE_HERE(prefix
, thread_prefix_finalize
);
3690 // We'll re-initialize these flags from the prefix list when we check for duplicates.
3691 prefix
->user
= false;
3692 prefix
->stable
= false;
3693 prefix
->ncp
= false;
3694 ppref
= &prefix
->next
;
3697 // On exit, ppref is pointing to the end-of-list pointer.
3699 // Add any prefixes that are not present.
3700 for (i
= 0; i
< prefixes
->num
; i
++) {
3701 cti_prefix_t
*cti_prefix
= prefixes
->prefixes
[i
];
3702 for (prefix
= thread_prefixes
; prefix
!= NULL
; prefix
= prefix
->next
) {
3703 if (!memcmp(&prefix
->prefix
, &cti_prefix
->prefix
, 16)) {
3707 if (prefix
== NULL
) {
3708 prefix
= thread_prefix_create(&cti_prefix
->prefix
, cti_prefix
->prefix_length
);
3709 if (prefix
== NULL
) {
3710 ERROR("cti_prefix_list_callback: no memory for prefix.");
3712 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, prefix_buf
);
3713 INFO("cti_prefix_list_callback: prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" showed up",
3714 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, prefix_buf
));
3716 ppref
= &prefix
->next
;
3719 // Also, since we're combing the list, update ncp, user and stable flags. Note that a prefix can
3720 // appear more than once in the thread prefix list.
3721 if (prefix
!= NULL
) {
3722 if (cti_prefix
->flags
& kCTIFlag_NCP
) {
3725 prefix
->user
= true;
3727 if (cti_prefix
->flags
& kCTIFlag_Stable
) {
3728 prefix
->stable
= true;
3733 // At this point the thread prefix list contains the same information as what we just received.
3734 // Trigger a "prefix set changed" event.
3735 partition_prefix_set_changed();
3740 get_thread_interface_list(void)
3742 #ifdef GET_TUNNEL_NAME_WITH_WPANCTL
3743 char *args
[] = { "list" };
3744 INFO("/usr/local/bin/wpanctl list");
3745 thread_interface_enumerator_process
= ioloop_subproc("/usr/local/bin/wpanctl", args
, 1,
3746 thread_interface_done
,
3747 thread_interface_output
, NULL
);
3748 if (thread_interface_enumerator_process
== NULL
) {
3749 ERROR("Unable to enumerate thread interfaces.");
3754 #endif // TARGET_OS_TV && !RA_TESTER
3756 #ifdef TCPDUMP_LOGGER
3758 tcpdump_output(io_t
*io
, void *__unused context
)
3760 static char inbuf
[1024];
3765 if (offset
+ 1 != sizeof(inbuf
)) {
3766 rv
= read(io
->fd
, &inbuf
[offset
], sizeof(inbuf
) - 1 - offset
);
3768 ERROR("tcpdump_output: " PUB_S_SRP
, strerror(errno
));
3772 INFO("Done with thread interface output.");
3779 if (offset
+ 1 == sizeof(inbuf
)) {
3782 s
= strchr(inbuf
, '\n');
3788 INFO(PUB_S_SRP
, inbuf
);
3789 if (s
!= &inbuf
[offset
]) {
3790 memmove(inbuf
, s
, &inbuf
[offset
] - s
);
3796 tcpdump_done(void *__unused context
, int status
, const char *error
)
3798 if (error
!= NULL
) {
3799 ERROR("tcpdump_done: " PUB_S_SRP
, error
);
3801 INFO("tcpdump_done: %d.", status
);
3803 ioloop_subproc_release(tcpdump_logger_process
);
3807 start_tcpdump_logger(void)
3809 char *args
[] = { "-vv", "-s", "1500", "-n", "-e", "-i", "utun0", "-l", "udp", "port", "53" };
3810 INFO("/usr/sbin/tcpdump -vv -s 1500 -n -e -i utun0 udp port 53");
3811 tcpdump_logger_process
= ioloop_subproc("/usr/sbin/tcpdump", args
, 11, tcpdump_done
,
3812 tcpdump_output
, NULL
);
3813 if (tcpdump_logger_process
== NULL
) {
3814 ERROR("Unable to start tcpdump logger.");
3817 #endif // TCPDUMP_LOGGER
3820 thread_network_startup(void)
3822 INFO("thread_network_startup: Thread network started.");
3824 #ifdef MONTIOR_ROUTING_SOCKET
3825 start_route_listener();
3828 nw_parameters_t params
= nw_parameters_create();
3829 if (path_evaluator
!= NULL
) {
3830 nw_path_evaluator_cancel(path_evaluator
);
3831 nw_release(path_evaluator
);
3833 path_evaluator
= nw_path_create_evaluator_for_listener(params
, &error
);
3835 if (path_evaluator
== NULL
|| error
!= 0) {
3836 ERROR("thread_network_startup: Unable to create network path evaluator.");
3839 nw_path_evaluator_set_update_handler(path_evaluator
, dispatch_get_main_queue(), ^(nw_path_t path
) {
3840 nw_path_event(path
);
3842 nw_path_t initial
= nw_path_evaluator_copy_path(path_evaluator
);
3843 nw_path_event(initial
);
3844 nw_release(initial
);
3845 #endif // MONITOR_ROUTING_SOCKET
3846 #if TARGET_OS_TV && !defined(RA_TESTER)
3847 get_thread_interface_list();
3849 set_thread_forwarding();
3850 #ifdef TCPDUMP_LOGGER
3851 start_tcpdump_logger();
3855 cti_get_state(&thread_state_context
, NULL
, cti_get_state_callback
, dispatch_get_main_queue());
3856 cti_get_network_node_type(&thread_role_context
, NULL
, cti_get_role_callback
, dispatch_get_main_queue());
3857 cti_get_service_list(&thread_service_context
, NULL
, cti_service_list_callback
, dispatch_get_main_queue());
3858 cti_get_prefix_list(&thread_prefix_context
, NULL
, cti_prefix_list_callback
, dispatch_get_main_queue());
3859 cti_get_tunnel_name(NULL
, cti_get_tunnel_name_callback
, dispatch_get_main_queue());
3860 cti_get_partition_id(&thread_partition_id_context
, NULL
, cti_get_partition_id_callback
, dispatch_get_main_queue());
3865 thread_network_shutdown(void)
3867 interface_t
*interface
;
3868 network_link_t
*link
;
3870 if (thread_state_context
) {
3871 INFO("thread_network_shutdown: discontinuing state events");
3872 cti_events_discontinue(thread_state_context
);
3874 if (thread_role_context
) {
3875 INFO("thread_network_shutdown: discontinuing role events");
3876 cti_events_discontinue(thread_role_context
);
3878 if (thread_service_context
) {
3879 INFO("thread_network_shutdown: discontinuing service events");
3880 cti_events_discontinue(thread_service_context
);
3882 if (thread_prefix_context
) {
3883 INFO("thread_network_shutdown: discontinuing prefix events");
3884 cti_events_discontinue(thread_prefix_context
);
3886 if (thread_partition_id_context
) {
3887 INFO("thread_network_shutdown: discontinuing partition ID events");
3888 cti_events_discontinue(thread_partition_id_context
);
3891 if (path_evaluator
!= NULL
) {
3892 nw_path_evaluator_cancel(path_evaluator
);
3893 nw_release(path_evaluator
);
3894 path_evaluator
= NULL
;
3896 INFO("thread_network_shutdown: Thread network shutdown.");
3897 // Stop all activity on interfaces.
3898 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
3899 interface_shutdown(interface
);
3901 for (link
= network_links
; link
; link
= link
->next
) {
3902 link
->primary
= NULL
;
3906 partition_state_reset();
3912 partition_state_reset(void)
3914 thread_prefix_t
*prefix
, *next_prefix
= NULL
;
3915 thread_service_t
*service
, *next_service
= NULL
;
3916 thread_pref_id_t
*pref_id
, *next_pref_id
= NULL
;
3918 // Remove any saved state from the thread network.
3919 for (prefix
= thread_prefixes
; prefix
!= NULL
; prefix
= next_prefix
) {
3920 next_prefix
= prefix
->next
;
3921 RELEASE_HERE(prefix
, thread_prefix_finalize
);
3923 thread_prefixes
= NULL
;
3925 if (published_thread_prefix
!= NULL
) {
3926 RELEASE_HERE(published_thread_prefix
, thread_prefix_finalize
);
3927 published_thread_prefix
= NULL
;
3929 if (adopted_thread_prefix
!= NULL
) {
3930 RELEASE_HERE(adopted_thread_prefix
, thread_prefix_finalize
);
3931 adopted_thread_prefix
= NULL
;
3934 for (service
= thread_services
; service
!= NULL
; service
= next_service
) {
3935 next_service
= service
->next
;
3936 RELEASE_HERE(service
, thread_service_finalize
);
3938 thread_services
= NULL
;
3940 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= next_pref_id
) {
3941 next_pref_id
= pref_id
->next
;
3942 RELEASE_HERE(pref_id
, thread_pref_id_finalize
);
3944 thread_pref_ids
= NULL
;
3946 current_thread_state
= kCTI_NCPState_Uninitialized
;
3947 current_thread_role
= kCTI_NetworkNodeType_Unknown
;
3949 partition_last_prefix_set_change
= 0;
3950 partition_last_pref_id_set_change
= 0;
3951 partition_last_partition_id_change
= 0;
3952 partition_last_role_change
= 0;
3953 partition_last_state_change
= 0;
3954 partition_settle_start
= 0;
3955 partition_service_last_add_time
= 0;
3956 partition_id_is_known
= false;
3957 partition_have_prefix_list
= false;
3958 partition_have_pref_id_list
= false;
3959 partition_tunnel_name_is_known
= false;
3960 partition_can_advertise_service
= false;
3961 partition_can_provide_routing
= false;
3962 partition_may_offer_service
= false;
3963 partition_settle_satisfied
= true;
3965 if (partition_settle_wakeup
!= NULL
) {
3966 ioloop_cancel_wake_event(partition_settle_wakeup
);
3969 if (partition_post_partition_wakeup
!= NULL
) {
3970 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
3973 if (partition_pref_id_wait_wakeup
!= NULL
) {
3974 ioloop_cancel_wake_event(partition_pref_id_wait_wakeup
);
3977 if (partition_service_add_pending_wakeup
!= NULL
) {
3978 ioloop_cancel_wake_event(partition_service_add_pending_wakeup
);
3983 prefcmp(uint8_t *a
, uint8_t *b
, int len
)
3986 for (i
= 0; i
< len
; i
++) {
3987 if (a
[i
] < b
[i
]) return -1;
3988 if (a
[i
] > b
[i
]) return 1;
3994 partition_prefix_remove_callback(void *__unused context
, cti_status_t status
)
3996 if (status
!= kCTIStatus_NoError
) {
3997 ERROR("partition_unpublish_my_prefix: failed to unpublish my prefix: %d.", status
);
3999 INFO("partition_unpublish_my_prefix: done unpublishing my prefix.");
4004 partition_stop_advertising_pref_id_done(void *__unused context
, cti_status_t status
)
4006 INFO("partition_stop_advertising_pref_id_done: %d", status
);
4010 partition_stop_advertising_pref_id(void)
4012 // This should remove any copy of the service that this BR is advertising.
4013 uint8_t service_info
[] = { 0, 0, 0, 1 };
4016 INFO("partition_stop_advertising_pref_id: %" PRIu64
"/%02x" , THREAD_ENTERPRISE_NUMBER
, service_info
[0]);
4017 service_info
[0] = THREAD_PREF_ID_OPTION
& 255;
4018 status
= cti_remove_service(NULL
, partition_stop_advertising_pref_id_done
,
4019 dispatch_get_main_queue(),
4020 THREAD_ENTERPRISE_NUMBER
, service_info
, 1);
4021 if (status
!= kCTIStatus_NoError
) {
4022 INFO("partition_stop_advertising_pref_id: status %d", status
);
4027 partition_advertise_pref_id_done(void *__unused context
, cti_status_t status
)
4029 INFO("partition_advertise_pref_id_done: %d", status
);
4033 partition_advertise_pref_id(uint8_t *prefix
)
4035 // This should remove any copy of the service that this BR is advertising.
4036 uint8_t service_info
[] = { 0, 0, 0, 1 };
4038 memcpy(pref_id
, thread_partition_id
, 4);
4039 memcpy(&pref_id
[4], prefix
, 5);
4040 uint8_t full_prefix
[6] = {0xfd, prefix
[0], prefix
[1], prefix
[2], prefix
[3], prefix
[4]};
4042 service_info
[0] = THREAD_PREF_ID_OPTION
& 255;
4043 IPv6_PREFIX_GEN_SRP(full_prefix
, sizeof(full_prefix
), prefix_buf
);
4044 INFO("partition_advertise_pref_id: %" PRIu64
"/%02x/%02x%02x%02x%02x" PRI_IPv6_PREFIX_SRP
,
4045 THREAD_ENTERPRISE_NUMBER
, service_info
[0], pref_id
[0], pref_id
[1], pref_id
[2], pref_id
[3],
4046 IPv6_PREFIX_PARAM_SRP(prefix_buf
));
4047 int status
= cti_add_service(NULL
, partition_advertise_pref_id_done
, dispatch_get_main_queue(),
4048 THREAD_ENTERPRISE_NUMBER
, service_info
, 1, pref_id
, sizeof pref_id
);
4049 if (status
!= kCTIStatus_NoError
) {
4050 INFO("partition_advertise_pref_id: status %d", status
);
4055 partition_id_update(void)
4057 thread_prefix_t
*advertised_prefix
= get_advertised_thread_prefix();
4058 if (advertised_prefix
== NULL
) {
4059 INFO("partition_id_update: no advertised prefix, not advertising pref:id.");
4060 } else if (advertised_prefix
== adopted_thread_prefix
) {
4061 INFO("partition_id_update: not advertising pref:id for adopted prefix.");
4062 partition_stop_advertising_pref_id();
4064 partition_advertise_pref_id(((uint8_t *)&advertised_prefix
->prefix
) + 1);
4065 INFO("partition_id_update: advertised pref:id for our prefix.");
4070 partition_unpublish_prefix(thread_prefix_t
*prefix
)
4072 cti_status_t status
= cti_remove_prefix(NULL
, partition_prefix_remove_callback
, dispatch_get_main_queue(),
4073 &prefix
->prefix
, 64);
4074 if (status
!= kCTIStatus_NoError
) {
4075 ERROR("partition_unpublish_prefix: prefix remove failed: %d.", status
);
4077 partition_stop_advertising_pref_id();
4081 partition_refresh_and_re_evaluate(void)
4083 refresh_interface_list();
4084 routing_policy_evaluate_all_interfaces(true);
4087 typedef struct unadvertised_prefix_remove_state unadvertised_prefix_remove_state_t
;
4088 struct unadvertised_prefix_remove_state
{
4089 int num_unadvertised_prefixes
;
4091 void (*continuation
)(void);
4095 partition_remove_all_prefixes_done(void *context
, cti_status_t status
)
4097 unadvertised_prefix_remove_state_t
*state
= context
;
4098 state
->num_removals
++;
4099 if (state
->num_removals
== state
->num_unadvertised_prefixes
) {
4100 INFO("partition_remove_all_prefixes_done: DONE: status = %d num_removals = %d num_unadvertised = %d",
4101 status
, state
->num_removals
, state
->num_unadvertised_prefixes
);
4102 void (*continuation
)(void) = state
->continuation
;
4104 if (continuation
!= NULL
) {
4107 INFO("partition_remove_all_prefixes_done: no continuation.");
4110 INFO("partition_remove_all_prefixes_done: !DONE: status = %d num_removals = %d num_unadvertised = %d",
4111 status
, state
->num_removals
, state
->num_unadvertised_prefixes
);
4116 partition_remove_all_unwanted_prefixes_inner(unadvertised_prefix_remove_state_t
*state
, thread_prefix_t
*prefix
)
4118 // Don't unpublish the adopted or published prefix.
4119 if ((published_thread_prefix
== NULL
|| memcmp(&published_thread_prefix
->prefix
, &prefix
->prefix
, 8)) &&
4120 (adopted_thread_prefix
== NULL
|| memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)))
4122 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, prefix_buf
);
4123 INFO("partition_remove_all_unwanted_prefixes: Removing prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4124 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, prefix_buf
));
4125 cti_status_t status
= cti_remove_prefix(state
, partition_remove_all_prefixes_done
,
4126 dispatch_get_main_queue(), &prefix
->prefix
, 64);
4127 if (status
!= kCTIStatus_NoError
) {
4128 ERROR("partition_remove_all_unwanted_prefixes: prefix remove failed: %d.", status
);
4134 partition_remove_all_unwanted_prefixes(void (*continuation
)(void), thread_prefix_t
*prefix_1
, thread_prefix_t
*prefix_2
)
4136 unadvertised_prefix_remove_state_t
*state
= calloc(1, sizeof(*state
));
4137 if (state
== NULL
) {
4138 INFO("partition_remove_all_unwanted_prefixes: no memory");
4142 // It's possible for us to get into a state where a prefix is published by this BR, but doesn't
4143 // have a pref:id and isn't recognized as belonging to this BR. This should never happen in practice,
4144 // but if it does happen, the only thing that will eliminate it is a reboot. In case this happens,
4145 // we go through the list of prefixes that are marked ncp and unpublish them.
4146 thread_prefix_t
*prefix
;
4148 state
->continuation
= continuation
;
4149 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4150 if (!partition_pref_id_is_present(&prefix
->prefix
)) {
4151 // It's possible for partition_remove_all_unwanted_prefixes to get called before we have a full list of
4152 // recently-published prefixes. It is possible for either the published prefix or the adopted prefix to
4153 // not be on the list of prefixes. The caller may however have wanted to change either of those pointers;
4154 // in this case, it will pass in either or both of those pointers as prefix_1 and prefix_2; if we see those
4155 // prefixes on the list, we don't need to unpublish them twice.
4156 if (prefix_1
!= NULL
&& !memcmp(&prefix
->prefix
, &prefix_1
->prefix
, 8)) {
4159 if (prefix_2
!= NULL
&& !memcmp(&prefix
->prefix
, &prefix_2
->prefix
, 8)) {
4162 state
->num_unadvertised_prefixes
++;
4165 if (prefix_1
!= NULL
) {
4166 state
->num_unadvertised_prefixes
++;
4168 if (prefix_2
!= NULL
) {
4169 state
->num_unadvertised_prefixes
++;
4172 // Now actually remove the prefixes.
4173 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4174 if (!partition_pref_id_is_present(&prefix
->prefix
)) {
4175 partition_remove_all_unwanted_prefixes_inner(state
, prefix
);
4178 if (prefix_1
!= NULL
) {
4179 partition_remove_all_unwanted_prefixes_inner(state
, prefix_1
);
4181 if (prefix_2
!= NULL
) {
4182 partition_remove_all_unwanted_prefixes_inner(state
, prefix_2
);
4185 // If we didn't remove any prefixes, continue immediately.
4186 if (state
->num_unadvertised_prefixes
== 0) {
4187 if (state
->continuation
) {
4188 state
->continuation();
4191 } else if (!state
->continuation
) {
4193 #ifdef __clang_analyzer__ // clang_analyzer is unable to follow the reference through the cti code.
4201 partition_unpublish_adopted_prefix(bool wait
)
4203 // Unpublish the adopted prefix
4204 if (adopted_thread_prefix
!= NULL
) {
4205 partition_unpublish_prefix(adopted_thread_prefix
);
4206 INFO("partition_unpublish_adopted_prefix: started to unadopt prefix.");
4207 RELEASE_HERE(adopted_thread_prefix
, thread_prefix_finalize
);
4208 adopted_thread_prefix
= NULL
;
4211 // Something changed, so do a routing policy update unless wait==true
4213 partition_refresh_and_re_evaluate();
4218 partition_publish_prefix_finish(void)
4220 INFO("partition_publish_prefix_finish: prefix unpublishing has completed, time to update the prefix.");
4222 partition_id_update();
4223 set_thread_prefix();
4225 // Something changed, so do a routing policy update.
4226 partition_refresh_and_re_evaluate();
4230 partition_publish_my_prefix()
4232 void (*continuation
)(void) = NULL
;
4233 thread_prefix_t
*prefix_1
= NULL
;
4234 thread_prefix_t
*prefix_2
= NULL
;
4236 if (adopted_thread_prefix
!= NULL
) {
4237 prefix_1
= adopted_thread_prefix
;
4238 adopted_thread_prefix
= NULL
;
4241 // If we already have a published thread prefix, it really should be my_thread_prefix.
4242 if (published_thread_prefix
!= NULL
) {
4243 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4244 // This should always be false.
4245 if (memcmp(&published_thread_prefix
->prefix
, &my_thread_prefix
, 8)) {
4246 INFO("partition_publish_my_prefix: Published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" is not my prefix",
4247 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4248 prefix_2
= published_thread_prefix
;
4249 published_thread_prefix
= NULL
;
4250 continuation
= partition_publish_prefix_finish
;
4252 INFO("partition_publish_my_prefix: Published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" is my prefix",
4253 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4256 if (published_thread_prefix
== NULL
) {
4257 // Publish the prefix
4258 published_thread_prefix
= thread_prefix_create(&my_thread_prefix
, 64);
4259 if (published_thread_prefix
== NULL
) {
4260 ERROR("partition_publish_my_prefix: No memory for locally-advertised thread prefix");
4263 continuation
= partition_publish_prefix_finish
;
4264 SEGMENTED_IPv6_ADDR_GEN_SRP(my_thread_prefix
.s6_addr
, prefix_buf
);
4265 INFO("partition_publish_my_prefix: Publishing my prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4266 SEGMENTED_IPv6_ADDR_PARAM_SRP(my_thread_prefix
.s6_addr
, prefix_buf
));
4268 partition_remove_all_unwanted_prefixes(continuation
, prefix_1
, prefix_2
);
4270 if (prefix_1
!= NULL
) {
4271 RELEASE_HERE(prefix_1
, thread_prefix_finalize
);
4273 if (prefix_2
!= NULL
) {
4274 RELEASE_HERE(prefix_2
, thread_prefix_finalize
);
4279 partition_adopt_prefix(thread_prefix_t
*prefix
)
4281 void (*continuation
)(void) = NULL
;
4282 thread_prefix_t
*prefix_1
= NULL
;
4283 thread_prefix_t
*prefix_2
= NULL
;
4285 if (published_thread_prefix
!= NULL
) {
4286 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4287 INFO("partition_adopt_prefix: Removing published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4288 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4289 prefix_1
= published_thread_prefix
;
4290 published_thread_prefix
= NULL
;
4293 // If we already have an advertised thread prefix, it might not have changed.
4294 if (adopted_thread_prefix
!= NULL
) {
4295 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4296 if (memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)) {
4297 INFO("partition_adopt_prefix: Removing previously adopted prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4298 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4299 prefix_2
= adopted_thread_prefix
;
4300 continuation
= partition_publish_prefix_finish
;
4302 INFO("partition_adopt_prefix: Keeping previously adopted prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4303 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4306 if (adopted_thread_prefix
== NULL
) {
4308 adopted_thread_prefix
= prefix
;
4309 RETAIN_HERE(adopted_thread_prefix
);
4310 continuation
= partition_publish_prefix_finish
;
4311 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4312 INFO("partition_adopt_prefix: Adopting prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4313 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4315 partition_remove_all_unwanted_prefixes(continuation
, prefix_1
, prefix_2
);
4317 if (prefix_1
!= NULL
) {
4318 RELEASE_HERE(prefix_1
, thread_prefix_finalize
);
4320 if (prefix_2
!= NULL
) {
4321 RELEASE_HERE(prefix_2
, thread_prefix_finalize
);
4325 // Check to see if a specific prefix is still present.
4327 partition_prefix_is_present(struct in6_addr
*address
, int length
)
4329 thread_prefix_t
*prefix
;
4330 // For now we assume that the comparison is as a /64.
4331 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4332 if (prefix
->prefix_len
== length
&& !memcmp((uint8_t *)&prefix
->prefix
, (uint8_t *)address
, 8)) {
4339 // Check to see if a valid pref:id for the specified prefix is present.
4341 partition_pref_id_is_present(struct in6_addr
*prefix_addr
)
4343 thread_pref_id_t
*pref_id
;
4344 uint8_t *prefix_bytes
= (uint8_t *)prefix_addr
;
4346 INFO("partition_pref_id_is_present: published_thread_prefix = %p; prefix = %p", published_thread_prefix
,
4349 // The published prefix's pref:id is always considered present.
4350 if (published_thread_prefix
!= NULL
&& !memcmp(prefix_addr
, &published_thread_prefix
->prefix
, 8)) {
4351 INFO("partition_pref_id_is_present: prefix is published prefix");
4355 for (pref_id
= thread_pref_ids
; pref_id
; pref_id
= pref_id
->next
) {
4356 // A pref:id is valid if the partition ID matches the current partition ID.
4357 // A pref:id matches a prefix if the 40 variable bits in the ULA /48 are the same.
4358 if (!memcmp(thread_partition_id
, pref_id
->partition_id
, 4) &&
4359 !memcmp(prefix_bytes
+ 1, pref_id
->prefix
, 5))
4361 INFO("partition_pref_id_is_present: pref:id is present");
4364 IPv6_PREFIX_GEN_SRP(pref_id
->prefix
, sizeof(pref_id
->prefix
), pref_id_prefix
);
4365 if (memcmp(thread_partition_id
, pref_id
->partition_id
, 4)) {
4366 INFO("partition_pref_id_is_present: "
4367 "pref:id for " PRI_IPv6_PREFIX_SRP
4368 ":%02x%02x%02x%02x does not match partition id %02x%02x%02x%02x",
4369 IPv6_PREFIX_PARAM_SRP(pref_id_prefix
),
4370 pref_id
->partition_id
[0], pref_id
->partition_id
[1], pref_id
->partition_id
[2],
4371 pref_id
->partition_id
[3],
4372 thread_partition_id
[0], thread_partition_id
[1], thread_partition_id
[2], thread_partition_id
[3]);
4374 INFO("partition_pref_id_is_present: "
4375 "pref:id for " PRI_IPv6_PREFIX_SRP
":%02x%02x%02x%02x does not match prefix %02x%02x%02x%02x%02x",
4376 IPv6_PREFIX_PARAM_SRP(pref_id_prefix
),
4377 pref_id
->partition_id
[0], pref_id
->partition_id
[1], pref_id
->partition_id
[2],
4378 pref_id
->partition_id
[3],
4379 prefix_bytes
[1], prefix_bytes
[2], prefix_bytes
[3], prefix_bytes
[4], prefix_bytes
[5]);
4386 // Find the lowest valid prefix present. The return value may be the published prefix.
4387 static thread_prefix_t
*
4388 partition_find_lowest_valid_prefix(void)
4390 thread_prefix_t
*prefix
, *lowest
= published_thread_prefix
;
4392 // Are there other prefixes published?
4393 for (prefix
= thread_prefixes
; prefix
!= NULL
; prefix
= prefix
->next
) {
4394 // The prefix we publish doesn't count.
4395 if (published_thread_prefix
!= NULL
&& !memcmp(&prefix
->prefix
, &published_thread_prefix
->prefix
, 8)) {
4398 if (partition_pref_id_is_present(&prefix
->prefix
)) {
4399 if (lowest
== NULL
|| memcmp(&prefix
->prefix
, &lowest
->prefix
, 8) < 0) {
4408 // Find the lowest valid pref:id. The return value may be the pref:id for the published prefix.
4409 static thread_pref_id_t
*
4410 partition_find_lowest_valid_pref_id(void)
4412 thread_pref_id_t
*lowest
= NULL
;
4413 thread_pref_id_t
*pref_id
;
4415 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= pref_id
->next
) {
4416 if (lowest
== NULL
|| memcmp(pref_id
->prefix
, lowest
->prefix
, 5) < 0) {
4423 // The prefix ID timeout has gone off. At this time we evaluate the state of the network: the fact that we
4424 // got a wakeup means that there has been no partition event and nothing has changed about the set of
4425 // prefixes published on the thread mesh since the wakeup was scheduled. We don't schedule this wakeup unless
4426 // there is more than one prefix on the thread mesh. So that means that when the wakeup is called, there
4427 // is still more than one prefix+pref:id pair active on the link--an undesirable situation. So we now
4428 // hold an election. If we lose, we drop our prefix+pref:id pair in favor of the winner. If we win,
4429 // we do nothing--we are expecting the BR(s) publishing the other prefix+pref:id pair(s) to drop them.
4431 partition_pref_id_timeout(void *__unused context
)
4433 thread_prefix_t
*prefix
= partition_find_lowest_valid_prefix();
4435 // This should never happen because we wouldn't have set the timeout.
4436 if (prefix
== NULL
) {
4437 INFO("partition_pref_id_timeout: no published prefix.");
4441 // If we won, do nothing.
4442 if (published_thread_prefix
!= NULL
&& (prefix
== published_thread_prefix
||
4443 !memcmp(&prefix
->prefix
, &published_thread_prefix
->prefix
, 8))) {
4444 INFO("partition_pref_id_timeout: published prefix is the lowest; keeping it.");
4448 // published_thread_prefix should never be null here.
4449 // If our published prefix is not the lowest prefix, then we should drop it and adopt the lowest prefix.
4450 if (published_thread_prefix
!= NULL
&& memcmp(&prefix
->prefix
, &published_thread_prefix
->prefix
, 8)) {
4451 INFO("partition_pref_id_timeout: published prefix is not lowest valid prefix. Adopting lowest valid prefix.");
4452 partition_adopt_prefix(prefix
);
4456 // We should never get here.
4457 if (adopted_thread_prefix
!= NULL
) {
4458 if (!memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)) {
4459 ERROR("partition_pref_id_timeout: no published prefix. Already adopted lowest.");
4462 // Unadopt this prefix since it's not lowest.
4463 partition_unpublish_adopted_prefix(false);
4464 // adopted_thread_prefix is now NULL
4467 // And we should never get here.
4468 ERROR("partition_pref_id_timeout: no published prefix. Adopting lowest.");
4469 partition_adopt_prefix(prefix
);
4472 // When we see a new partition, if there isn't a prefix to adopt and we aren't publishing one,
4473 // we wait n seconds to see if some other BR publishes a prefix, but also publish our own pref:id.
4474 // If no router on the partition is publishing a prefix, then after n seconds we hold an election,
4475 // choosing the pref:id with the lowest ULA. If that's this router, then we will publish our prefix,
4476 // but if not, we want to check after a bit to make sure a prefix /does/ get published. If after
4477 // another n seconds, we still don't see a valid prefix+pref:id pair, we publish our own; if this
4478 // later turns out to have been a mistake, we will hold the election again and remove the one we
4479 // published if we don't win.
4481 partition_post_election_wakeup(void *__unused context
)
4483 thread_prefix_t
*prefix
= partition_find_lowest_valid_prefix();
4485 // There is no valid prefix published. Publish ours.
4486 if (prefix
== NULL
) {
4487 INFO("partition_post_election_wakeup: no valid thread prefix present, publishing mine.");
4488 partition_publish_my_prefix();
4492 // It's perfectly valid to not have adopted the lowest prefix at this point.
4493 // However, if we have adopted a prefix, we shouldn't be here because the timeout should have been
4495 if (adopted_thread_prefix
!= NULL
&& memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)) {
4496 ERROR("partition_post_election_wakeup: adopted prefix is not lowest.");
4498 ERROR("partition_post_election_wakeup: adopted prefix is lowest.");
4502 // This is the initial wakeup as described under partition_post_election_wakeup. At this time
4503 // if there is a valid published pref:id pair, we adopt it; if not, then we hold an election based
4504 // on all of the on-partition pref:id pairs that we see. If we win, we publish our prefix; otherwise
4505 // give the winner time to publish its prefix.
4507 partition_post_partition_timeout(void *__unused context
)
4509 thread_prefix_t
*prefix
= partition_find_lowest_valid_prefix();
4510 thread_pref_id_t
*pref_id
;
4512 // Is there a prefix+pref:id published?
4513 // Actually at this point we should already have adopted it and the wakeup should have been canceled.
4514 if (prefix
!= NULL
) {
4515 ERROR("partition_post_partition_timeout: wakeup when there's a valid lowest prefix.");
4519 // Are there pref:id services published that list a lower ULA than ours?
4520 pref_id
= partition_find_lowest_valid_pref_id();
4522 if (pref_id
== NULL
) {
4523 INFO("There are no prefixes published, publishing my prefix.");
4524 partition_publish_my_prefix();
4528 // If not, publish ours.
4529 if (memcmp(((uint8_t *)&my_thread_prefix
) + 1, pref_id
->prefix
, 5) < 0) {
4530 INFO("partition_post_partition_timeout: my prefix id is lowest, publishing my prefix.");
4531 partition_publish_my_prefix();
4535 // If so, wait another ten seconds to see if one of them publishes a prefix
4536 // If we have adopted a prefix, set a timer after which we will drop it and start advertising if nothing has
4538 if (partition_post_partition_wakeup
!= NULL
) { // shouldn't be!
4539 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
4541 partition_post_partition_wakeup
= ioloop_wakeup_create();
4542 if (partition_post_partition_wakeup
== NULL
) {
4543 ERROR("partition_post_partition_timeout: can't allocate pref:id wait wakeup.");
4547 // Allow ten seconds for the services state to settle, after which time we should either have a pref:id backing
4548 // up a prefix, or should advertise a prefix.
4549 INFO("partition_post_partition_timeout: waiting for other BR to publish its prefixes.");
4550 ioloop_add_wake_event(partition_post_partition_wakeup
, NULL
, partition_post_election_wakeup
, NULL
, 10 * 1000);
4554 partition_proxy_listener_ready(void *__unused context
, uint16_t port
)
4556 INFO("partition_proxy_listener_ready: listening on port %d", port
);
4557 srp_service_listen_port
= port
;
4558 if (have_non_thread_interface
) {
4559 partition_can_advertise_service
= true;
4560 partition_maybe_advertise_service();
4562 partition_discontinue_srp_service();
4567 partition_start_srp_listener(void)
4569 const int max_avoid_ports
= 100;
4570 uint16_t avoid_ports
[max_avoid_ports
];
4571 int num_avoid_ports
= 0;
4572 thread_service_t
*service
;
4574 for (service
= thread_services
; service
; service
= service
->next
) {
4575 // Track the port regardless.
4576 if (num_avoid_ports
< max_avoid_ports
) {
4577 avoid_ports
[num_avoid_ports
] = (service
->port
[0] << 8) | (service
->port
[1]);
4582 INFO("partition_start_srp_listener: starting listener.");
4583 srp_listener
= srp_proxy_listen("local", avoid_ports
, num_avoid_ports
, partition_proxy_listener_ready
);
4584 if (srp_listener
== NULL
) {
4585 ERROR("partition_start_srp_listener: Unable to start SRP Proxy listener, so can't advertise it");
4591 partition_discontinue_srp_service()
4593 if (srp_listener
!= NULL
) {
4594 srp_proxy_listener_cancel(srp_listener
);
4595 srp_listener
= NULL
;
4599 memset(&srp_listener_ip_address
, 0, 16);
4600 srp_service_listen_port
= 0;
4601 partition_can_advertise_service
= false;
4603 // Stop advertising the service, if we are doing so.
4604 partition_stop_advertising_service();
4607 // An address on utun0 has changed. Evaluate what to do with our listener service.
4608 // This gets called from ifaddr_callback(). If we don't yet have a thread service configured,
4609 // it should be called for unchanged addresses as well as changed.
4611 partition_utun0_address_changed(const struct in6_addr
*addr
, enum interface_address_change change
)
4613 thread_prefix_t
*advertised_prefix
= NULL
;
4615 // Figure out what our current prefix is.
4616 if (published_thread_prefix
!= NULL
) {
4617 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4618 INFO("partition_utun0_address_changed: advertised prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" is my prefix.",
4619 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4620 advertised_prefix
= published_thread_prefix
;
4621 } else if (adopted_thread_prefix
!= NULL
) {
4622 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4623 INFO("partition_utun0_address_changed: advertised prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
4624 " is another router's prefix.",
4625 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4626 advertised_prefix
= adopted_thread_prefix
;
4629 SEGMENTED_IPv6_ADDR_GEN_SRP(addr
, addr_buf
);
4630 // Is this the address we are currently using?
4631 if (!memcmp(&srp_listener_ip_address
, addr
, 16)) {
4632 // Did it go away? If so, drop the listener.
4633 if (change
== interface_address_deleted
) {
4634 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
": listener address removed.",
4635 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4636 if (srp_listener
!= NULL
) {
4637 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4638 ": canceling listener on removed address.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4639 partition_discontinue_srp_service();
4642 // This should never happen.
4643 if (change
== interface_address_added
) {
4644 ERROR("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4645 ": address we're listening on was added.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4648 // Is it on the prefix we're currently publishing?
4649 if (advertised_prefix
!= NULL
&& !memcmp(&advertised_prefix
->prefix
, addr
, 8)) {
4650 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4651 ": listener address is on the advertised prefix--no action needed.",
4652 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4654 // In this case hopefully we'll get a new IP address we _can_ listen on in a subsequent call.
4655 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4656 ": listener address is not on the advertised prefix--no action taken.",
4657 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4661 // In no case can we do anything further.
4665 // If we have a prefix, see if we need to do anything.
4666 if (advertised_prefix
!= NULL
) {
4667 // If this is not the address we are currently using, and it showed up, is it on the prefix we
4669 if (!memcmp(&advertised_prefix
->prefix
, addr
, 8)) {
4670 // If we are not listening on an address, or we are listening on an address that isn't on the
4671 // prefix we are advertising, we need to stop, if needed, and start up a new listener.
4672 if (srp_listener_ip_address
.s6_addr
[0] == 0 ||
4673 memcmp(&advertised_prefix
->prefix
, &srp_listener_ip_address
, 8))
4675 // See if we already have a listener; if so, stop it.
4676 if (srp_listener_ip_address
.s6_addr
[0] != 0) {
4677 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
": stopping old listener.",
4678 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4679 srp_proxy_listener_cancel(srp_listener
);
4680 srp_listener
= NULL
;
4682 if (srp_listener
== NULL
) {
4683 if (!have_non_thread_interface
) {
4684 INFO("partition_utun0_address_changed: not starting a listener because we have no infrastructure");
4686 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
": starting a new listener.",
4687 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4688 memcpy(&srp_listener_ip_address
, addr
, 16);
4689 srp_service_listen_port
= 0;
4690 partition_start_srp_listener();
4695 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4696 ": this address not on advertised prefix, so no action to take.",
4697 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4700 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4701 ": no advertised prefix, so no action to take.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4705 // We call this function to see if we have a complete, recent set of information; if not, we wait a bit for the set
4706 // to become complete, but after 500ms we assume it won't be and proceed.
4708 partition_wait_for_prefix_settling(wakeup_callback_t callback
, uint64_t now
)
4710 // Remember when we started waiting for the partition data to settle.
4711 if (partition_settle_satisfied
) {
4712 partition_settle_start
= now
;
4713 partition_settle_satisfied
= false;
4716 if (partition_settle_wakeup
!= NULL
) {
4717 ioloop_cancel_wake_event(partition_settle_wakeup
);
4720 // If we aren't able to offer service, just wait.
4721 if (!partition_may_offer_service
) {
4722 INFO("partition_wait_for_prefix_settling: not able to offer service--deferring.");
4726 // If we've gotten updates on everything, we're good to go. The reason for comparing against
4727 // partition_settle_start is that if we've been seriously throttled for some reason, it might take
4728 // more than 500ms to get a callback, even though all the events came in between when we asked
4729 // for the initial callback and when we got it. Tunnel ID shouldn't change after startup.
4730 if (partition_last_prefix_set_change
>= partition_settle_start
&&
4731 partition_last_pref_id_set_change
>= partition_settle_start
&&
4732 partition_last_partition_id_change
>= partition_settle_start
&&
4733 partition_last_role_change
>= partition_settle_start
&&
4734 partition_last_state_change
>= partition_settle_start
&& partition_tunnel_name_is_known
)
4736 partition_settle_satisfied
= true;
4737 INFO("partition_wait_for_prefix_settling: satisfied after %llums.", now
- partition_settle_start
);
4738 return false; // means don't wait
4741 // If we've waited longer than 500ms and aren't satisfied, complain, but then proceed.
4742 if (now
- partition_settle_start
>= 500) {
4743 ERROR("partition_wait_for_prefix_settling: unsatisfied after %llums", now
- partition_settle_start
);
4744 partition_settle_satisfied
= true; // not really, but there's always next time.
4745 return false; // proceed if possible.
4748 // Otherwise, wake up 500ms after we started waiting for things to settle, and reconnoiter.
4749 if (partition_settle_wakeup
== NULL
) {
4750 partition_settle_wakeup
= ioloop_wakeup_create();
4751 if (partition_settle_wakeup
== NULL
) {
4752 ERROR("partition_wait_for_prefix_settling: Unable to postpone partition settlement wakeup: no memory.");
4753 partition_settle_satisfied
= true;
4757 ioloop_add_wake_event(partition_settle_wakeup
, NULL
, callback
, NULL
, 500 - (int)(now
- partition_settle_start
));
4762 partition_got_tunnel_name(void)
4764 partition_tunnel_name_is_known
= true;
4765 refresh_interface_list();
4768 // We have a recent prefix list and either have a recent pref:id list or one probably isn't coming.
4770 partition_prefix_list_or_pref_id_list_changed(void *__unused context
)
4772 // If we haven't had a pref:id update recently, wait a bit to see if one came with the most recent network data.
4773 if (partition_wait_for_prefix_settling(partition_prefix_list_or_pref_id_list_changed
, ioloop_timenow())) {
4774 ERROR("partition_prefix_list_or_pref_id_list_changed: waiting for prefix info to settle.");
4778 // If we aren't ready to advertise service, do nothing.
4779 if (!partition_may_offer_service
) {
4780 INFO("partition_prefix_list_or_pref_id_list_changed can't offer service yet.");
4784 // If there are no prefixes, then it doesn't matter what's on the prefix ID list: publish a prefix now.
4785 if (thread_prefixes
== NULL
) {
4786 INFO("partition_prefix_list_or_pref_id_list_changed have no prefixes, publishing my prefix");
4787 partition_publish_my_prefix();
4791 // It is a failure of the thread network software for us to get to this point without knowing the thread
4792 // partition ID. We should have received it on startup. So the case where this would happen would be if
4793 // on startup we simply didn't get it, which should never happen. What we'll do if this happens is make
4795 if (partition_id_is_known
== false) {
4796 ERROR("partition_prefix_list_or_pref_id_list_changed: partition ID never showed up!");
4799 // If we are already publishing a prefix and pref:id, we don't have to do anything to the prefix right now.
4800 if (published_thread_prefix
!= NULL
) {
4801 // We do need to trigger an interface scan though.
4802 refresh_interface_list();
4804 // Also, if there's more than one prefix present, set a timer for an hour from now, at which point we will
4805 // consider dropping our prefix.
4806 if (thread_prefixes
!= NULL
&& thread_prefixes
->next
!= NULL
) {
4807 INFO("partition_prefix_list_or_pref_id_list_changed:"
4808 "published prefix is unchanged, setting up the pref:id timer");
4809 if (partition_pref_id_wait_wakeup
!= NULL
) {
4810 ioloop_cancel_wake_event(partition_pref_id_wait_wakeup
);
4812 partition_pref_id_wait_wakeup
= ioloop_wakeup_create();
4813 if (partition_pref_id_wait_wakeup
== NULL
) {
4814 ERROR("partition_prefix_list_or_pref_id_list_changed: "
4815 "Unable to set a timer to wake up after the an hour to check the partition id.");
4819 // The thread network can be pretty chaotic right after the BR comes up, so if we see a partition during the
4820 // first 60 seconds, don't treat it as a real partition event, and do the re-election in 60 seconds rather
4822 uint64_t time_since_zero
= ioloop_timenow() - partition_last_state_change
;
4823 uint32_t pref_id_timeout_time
= 3600 * 1000;
4824 if (time_since_zero
< 60 * 1000) {
4825 pref_id_timeout_time
= 60 * 1000;
4827 ioloop_add_wake_event(partition_pref_id_wait_wakeup
, NULL
, partition_pref_id_timeout
, NULL
,
4828 pref_id_timeout_time
);
4829 INFO("added partition pref id timeout");
4831 INFO("partition_prefix_list_or_pref_id_list_changed: published prefix is unchanged");
4836 // If we have adopted a prefix and the prefix and pref:id are still present, do nothing.
4837 if (adopted_thread_prefix
!= NULL
) {
4838 if (partition_prefix_is_present(&adopted_thread_prefix
->prefix
, adopted_thread_prefix
->prefix_len
) &&
4839 partition_pref_id_is_present(&adopted_thread_prefix
->prefix
))
4841 INFO("partition_prefix_list_or_pref_id_list_changed: adopted prefix is unchanged");
4844 // If the adopted prefix is no longer present, stop using it.
4845 partition_unpublish_adopted_prefix(false);
4846 // adopted_thread_prefix is now NULL.
4849 // If there is a prefix present for which there is already a matching pref:id, adopt that prefix and pref:id now.
4850 // drop the thread_post_partition_timeout timer.
4851 thread_prefix_t
*prefix
;
4852 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4853 if (partition_pref_id_is_present(&prefix
->prefix
)) {
4854 INFO("partition_prefix_list_or_pref_id_list_changed: adopting new prefix");
4855 partition_adopt_prefix(prefix
);
4856 // When we adopt a prefix, it was already on-link, and quite possibly we already have an address
4857 // configured on that prefix on utun0. Calling refresh_interface_list() will trigger the listener
4858 // if in fact that's the case. If the address hasn't come up on utun0 yet, then when it comes up
4859 // that will trigger the listener.
4860 refresh_interface_list();
4863 if (partition_post_partition_wakeup
!= NULL
) {
4864 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
4868 // At this point there is a prefix, but no pref:id, and it's /not/ the prefix that we published. This
4869 // means that a partition has happened and the BR that published the prefix is on the other partition,
4870 // or else that the BR that published the prefix has gone offline and has been offline for at least
4872 // It's possible that either condition will heal, but in the meantime publish a prefix. The reason for
4873 // the urgency is that if we have a partition, and both routers are still online, then routing will be
4874 // screwed up until we publish a new prefix and migrate all the accessories on our partition to the
4876 INFO("partition_publish_prefix: there is a prefix, but no pref:id, so it's stale. Publishing my prefix.");
4877 partition_publish_my_prefix();
4880 // The list of published prefix has changed. Evaluate what to do with our partition state.
4881 // Mostly what we do when the prefix list changes is the same as what we do if the pref:id list
4882 // changes, but if we get an empty prefix list, it doesn't matter what's on the pref:id list,
4883 // so we act immediately.
4885 partition_prefix_set_changed(void)
4887 // Time stamp most recent prefix set update.
4888 partition_last_prefix_set_change
= ioloop_timenow();
4890 // Otherwise, we have a prefix list and a pref:id list, so we can make decisions.
4891 partition_prefix_list_or_pref_id_list_changed(NULL
);
4894 // The set of published pref:id's changed. Evaluate what to do with our pref:id
4896 partition_pref_id_set_changed(void)
4898 // Time stamp most recent prefix set update.
4899 partition_last_prefix_set_change
= ioloop_timenow();
4901 // Otherwise, we have a prefix list and a pref:id list, so we can make decisions.
4902 partition_prefix_list_or_pref_id_list_changed(NULL
);
4905 // The partition ID changed.
4907 partition_id_changed(void)
4909 partition_last_partition_id_change
= ioloop_timenow();
4911 // If we've never seen a partition ID before, this is not (necessarily) a partition.
4912 if (!partition_id_is_known
) {
4913 INFO("partition_id_changed: first time through.");
4914 partition_id_is_known
= true;
4918 // If we get a partition ID when we aren't a router, we should (I think!) ignore it.
4919 if (!partition_can_provide_routing
) {
4920 INFO("partition_id_changed: we aren't able to offer routing yet, so ignoring.");
4924 // If we are advertising a prefix, update our pref:id
4925 if (published_thread_prefix
!= NULL
) {
4926 INFO("partition_id_changed: updating advertised prefix id");
4927 partition_id_update();
4928 // In principle we didn't change anything material to the routing subsystem, so no need to re-evaluate current
4933 // Propose our prefix as a possible lowest prefix in case there's an election.
4934 partition_stop_advertising_pref_id();
4935 partition_advertise_pref_id(((uint8_t *)(&my_thread_prefix
)) + 1);
4937 // If we have adopted a prefix, set a timer after which we will drop it and start advertising if nothing has
4939 if (partition_post_partition_wakeup
!= NULL
) {
4940 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
4942 partition_post_partition_wakeup
= ioloop_wakeup_create();
4943 if (partition_post_partition_wakeup
== NULL
) {
4944 ERROR("partition_id_changed: can't allocate pref:id wait wakeup.");
4948 // Allow ten seconds for the services state to settle, after which time we should either have a pref:id backing
4949 // up a prefix, or should advertise a prefix.
4950 INFO("partition_id_changed: waiting for other BRs to propose their prefixes.");
4951 ioloop_add_wake_event(partition_post_partition_wakeup
, NULL
, partition_post_partition_timeout
, NULL
, 10 * 1000);
4955 partition_remove_service_done(void *context
, cti_status_t status
)
4957 INFO("partition_remove_service_done: %d", status
);
4959 // Flush any advertisements we're currently doing, since the accessories that advertised them will
4960 // notice the service is gone and start advertising with a different service.
4962 // The conditional test is so that we don't do this twice when we are advertising both services.
4964 if (context
!= NULL
) {
4970 partition_stop_advertising_service(void)
4972 // This should remove any copy of the service that this BR is advertising.
4973 INFO("partition_stop_advertising_service: %" PRIu64
"/" PUB_S_SRP
, THREAD_ENTERPRISE_NUMBER
, "00010001");
4974 uint8_t service_info
[] = { 0, 0, 0, 1 };
4977 service_info
[0] = THREAD_SRP_SERVER_OPTION
& 255;
4978 status
= cti_remove_service((void *)(ptrdiff_t)1, partition_remove_service_done
, dispatch_get_main_queue(),
4979 THREAD_ENTERPRISE_NUMBER
, service_info
, 1);
4980 if (status
!= kCTIStatus_NoError
) {
4981 INFO("partition_stop_advertising_service: status %d", status
);
4986 partition_add_service_callback(void *__unused context
, cti_status_t status
)
4988 if (status
!= kCTIStatus_NoError
) {
4989 INFO("partition_add_service_callback: status = %d", status
);
4991 INFO("partition_add_service_callback: status = %d", status
);
4996 partition_start_advertising_service(void)
4998 uint8_t service_info
[] = {0, 0, 0, 1};
4999 uint8_t server_info
[18];
5002 memcpy(&server_info
, &srp_listener_ip_address
, 16);
5003 server_info
[16] = (srp_service_listen_port
>> 8) & 255;
5004 server_info
[17] = srp_service_listen_port
& 255;
5006 service_info
[0] = THREAD_SRP_SERVER_OPTION
& 255;
5007 INFO("partition_add_srp_service: %" PRIu64
"/%02x/" PRI_SEGMENTED_IPv6_ADDR_SRP
":%d" ,
5008 THREAD_ENTERPRISE_NUMBER
, service_info
[0],
5009 SEGMENTED_IPv6_ADDR_PARAM_SRP(srp_listener_ip_address
.s6_addr
, server_ip_buf
), srp_service_listen_port
);
5011 ret
= cti_add_service(NULL
, partition_add_service_callback
, dispatch_get_main_queue(),
5012 THREAD_ENTERPRISE_NUMBER
, service_info
, 1, server_info
, sizeof server_info
);
5013 if (ret
!= kCTIStatus_NoError
) {
5014 INFO("partition_add_srp_service: status %d", ret
);
5017 // Wait a while for the service add to be reflected in an event.
5018 partition_schedule_service_add_wakeup();
5022 partition_service_add_wakeup(void *__unused context
)
5024 partition_service_last_add_time
= 0;
5025 partition_maybe_advertise_service();
5029 partition_schedule_service_add_wakeup()
5031 if (partition_service_add_pending_wakeup
== NULL
) {
5032 partition_service_add_pending_wakeup
= ioloop_wakeup_create();
5033 if (partition_service_add_pending_wakeup
== NULL
) {
5034 ERROR("Can't schedule service add pending wakeup: no memory!");
5038 ioloop_cancel_wake_event(partition_service_add_pending_wakeup
);
5040 // Wait ten seconds.
5041 ioloop_add_wake_event(partition_service_add_pending_wakeup
, NULL
, partition_service_add_wakeup
, NULL
, 10 * 1000);
5045 partition_maybe_advertise_service(void)
5047 thread_service_t
*service
, *lowest
[2];
5048 int num_services
= 0;
5050 bool should_remove_service
= false;
5051 bool should_advertise_service
= false;
5052 int64_t last_add_time
;
5054 // If we aren't ready to advertise a service, there's nothing to do.
5055 if (!partition_can_advertise_service
) {
5056 INFO("partition_maybe_advertise_service: no service to advertise yet.");
5060 if (partition_service_blocked
) {
5061 INFO("partition_maybe_advertise_service: service advertising is disabled.");
5065 for (i
= 0; i
< 16; i
++) {
5066 if (srp_listener_ip_address
.s6_addr
[i
] != 0) {
5071 INFO("partition_maybe_advertise_service: no listener.");
5075 // The add service function requires a remove prior to the add, so if we are doing an add, we need to wait
5076 // for things to stabilize before allowing the removal of a service to trigger a re-evaluation.
5077 // Therefore, if we've done an add in the past ten seconds, wait ten seconds before trying another add.
5078 last_add_time
= ioloop_timenow() - partition_service_last_add_time
;
5079 INFO("partition_maybe_advertise_service: last_add_time = %" PRId64
, last_add_time
);
5080 if (last_add_time
< 10 * 1000) {
5081 partition_schedule_service_add_wakeup();
5087 for (service
= thread_services
; service
; service
= service
->next
) {
5088 int port
= service
->port
[0] | (service
->port
[1] << 8);
5089 SEGMENTED_IPv6_ADDR_GEN_SRP(service
->address
, srv_addr_buf
);
5091 // A service only counts if its prefix is present and its prefix id is present and matches the
5092 // current partition id.
5093 if (partition_prefix_is_present((struct in6_addr
*)service
->address
, 64)) {
5094 if (partition_pref_id_is_present((struct in6_addr
*)service
->address
)) {
5096 for (i
= 0; i
< 2; i
++) {
5097 if (lowest
[i
] == NULL
) {
5098 lowest
[i
] = service
;
5099 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d goes in open slot %d.",
5100 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
, i
);
5102 } else if (memcmp(service
->address
, lowest
[i
]->address
, 16) < 0) {
5105 if (lowest
[1] != NULL
) {
5106 lowport
= (lowest
[1]->port
[0] << 8) | lowest
[1]->port
[1];
5107 SEGMENTED_IPv6_ADDR_GEN_SRP(lowest
[1]->address
, lowest_1_buf
);
5108 INFO("Superseding " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d in slot 1",
5109 SEGMENTED_IPv6_ADDR_PARAM_SRP(lowest
[1]->address
, lowest_1_buf
), lowport
);
5112 lowport
= (lowest
[0]->port
[0] << 8)| lowest
[0]->port
[1];
5113 SEGMENTED_IPv6_ADDR_GEN_SRP(lowest
[0]->address
, lowest_0_buf
);
5114 INFO("Moving " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d from slot 0 to slot 1",
5115 SEGMENTED_IPv6_ADDR_PARAM_SRP(lowest
[0]->address
, lowest_0_buf
), lowport
);
5116 lowest
[1] = lowest
[0];
5118 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d goes in slot %d.",
5119 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
, i
);
5120 lowest
[i
] = service
;
5125 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d doesn't count because the pref:id is not present.",
5126 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
);
5129 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d doesn't count because the prefix is not present.",
5130 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
);
5134 should_remove_service
= true;
5135 for (i
= 0; i
< 2; i
++) {
5136 if (lowest
[i
] == NULL
) {
5137 INFO("partition_maybe_advertise_service: adding service because there's an open slot.");
5138 should_remove_service
= false;
5139 should_advertise_service
= true;
5142 int sign
= memcmp(((uint8_t *)(&srp_listener_ip_address
)), lowest
[i
]->address
, 16);
5144 // We're already advertising the service and we win the election.
5145 // If the port hasn't changed, don't update the service
5146 uint16_t port
= (lowest
[i
]->port
[0] << 8) | lowest
[i
]->port
[1];
5147 if (port
!= srp_service_listen_port
) {
5148 INFO("partition_maybe_advertise_service: old service was present and prefix would win election.");
5149 should_remove_service
= false;
5150 should_advertise_service
= true;
5152 INFO("partition_maybe_advertise_service: service already present and would win election.");
5153 should_remove_service
= false;
5154 should_advertise_service
= false;
5157 } else if (sign
< 0) {
5158 INFO("partition_maybe_advertise_service: service not present but wins election.");
5159 should_remove_service
= false;
5160 should_advertise_service
= true;
5163 INFO("Service would not win election with lowest[%d]", i
);
5168 // Always remove service before adding it, but also remove it if it lost the election.
5169 if (should_remove_service
) {
5170 partition_stop_advertising_service();
5171 partition_service_last_add_time
= ioloop_timenow();
5173 if (should_advertise_service
) {
5174 partition_start_advertising_service();
5175 partition_service_last_add_time
= ioloop_timenow();
5180 partition_service_set_changed()
5182 partition_pref_id_set_changed();
5183 partition_maybe_advertise_service();
5186 static void partition_maybe_enable_services()
5188 bool am_associated
= current_thread_state
== kCTI_NCPState_Associated
;
5189 if (am_associated
) {
5190 INFO("partition_maybe_enable_services: "
5191 "Enabling service, which was disabled because of the thread role or state.");
5192 partition_may_offer_service
= true;
5193 partition_can_provide_routing
= true;
5194 refresh_interface_list();
5195 partition_prefix_list_or_pref_id_list_changed(NULL
);
5196 routing_policy_evaluate_all_interfaces(true);
5198 INFO("partition_maybe_enable_services: Not enabling service: " PUB_S_SRP
,
5199 am_associated
? "associated" : "!associated");
5203 static void partition_disable_service()
5205 bool done_something
= false;
5207 // When our node type or state is such that we should no longer be publishing a prefix, the NCP will
5208 // automatically remove the published prefix. In case this happens, we do not want to remember the
5209 // prefix as already having been published. So drop our recollection of the adopted and published
5210 // prefixes; this will get cleaned up when the network comes back if there's an inconsistency.
5211 if (adopted_thread_prefix
!= NULL
) {
5212 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
5213 INFO("partition_disable_service: unadopting prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
5214 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
5215 RELEASE_HERE(adopted_thread_prefix
, thread_prefix_finalize
);
5216 adopted_thread_prefix
= NULL
;
5217 done_something
= true;
5219 if (published_thread_prefix
!= NULL
) {
5220 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
5221 INFO("partition_disable_service: un-publishing prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
5222 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
5223 RELEASE_HERE(published_thread_prefix
, thread_prefix_finalize
);
5224 published_thread_prefix
= NULL
;
5225 done_something
= true;
5228 // We want to always say something when we pass through this state.
5229 if (!done_something
) {
5230 INFO("partition_disable_service: nothing to do.");
5233 partition_may_offer_service
= false;
5234 partition_can_provide_routing
= false;
5241 // c-file-style: "bsd"
5242 // c-basic-offset: 4
5244 // indent-tabs-mode: nil