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 flush_stale_routers(interface
, now
);
834 // See if we need a new prefix on the interface.
835 interface_prefix_evaluate(interface
);
839 adjust_router_received_time(interface_t
*const interface
, const uint64_t now
, const int64_t time_adjusted
)
841 icmp_message_t
*router
;
843 for (router
= interface
->routers
; router
!= NULL
; router
= router
->next
) {
844 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, __router_src_addr_buf
);
845 // Only adjust the received time once.
846 if (router
->received_time_already_adjusted
) {
847 DEBUG("adjust_router_received_time: received time already adjusted - remaining time: %llu, "
848 "router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
, (now
- router
->received_time
) / MSEC_PER_SEC
,
849 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_addr_buf
));
852 require_action_quiet(
853 (time_adjusted
> 0 && (UINT64_MAX
- now
) > (uint64_t)time_adjusted
) ||
854 (time_adjusted
< 0 && now
> ((uint64_t)-time_adjusted
)), exit
,
855 ERROR("adjust_router_received_time: invalid adjusted values is causing overflow - "
856 "now: %" PRIu64
", time_adjusted: %" PRId64
, now
, time_adjusted
));
857 router
->received_time
= now
+ time_adjusted
;
858 router
->received_time_already_adjusted
= true; // Only adjust the icmp message received time once.
859 DEBUG("adjust_router_received_time: router received time is adjusted - router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
860 ", adjusted value: %" PRId64
,
861 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_addr_buf
), time_adjusted
);
869 make_all_routers_nearly_stale(interface_t
*interface
, uint64_t now
)
871 // Make every router go stale in 19.999 seconds. This means that if we don't get a response
872 // to our solicit in 20 seconds, then when the timeout callback is called, there will be no
873 // routers on the interface that aren't stale, which will trigger router discovery.
874 adjust_router_received_time(interface
, now
, 19999 - 600 * MSEC_PER_SEC
);
878 vicarious_discovery_callback(void *context
)
880 interface_t
*interface
= context
;
881 INFO("Vicarious router discovery finished on " PUB_S_SRP
".", interface
->name
);
882 interface
->vicarious_router_discovery_in_progress
= false;
883 // At this point, policy evaluate will show all the routes that were present before vicarious
884 // discovery as stale, so policy_evaluate will start router discovery if we didn't get any
885 // RAs containing on-link prefixes.
886 routing_policy_evaluate(interface
, false);
891 routing_policy_evaluate_all_interfaces(bool assume_changed
)
893 interface_t
*interface
;
895 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
896 routing_policy_evaluate(interface
, assume_changed
);
902 routing_policy_evaluate(interface_t
*interface
, bool assume_changed
)
904 icmp_message_t
*router
;
905 bool new_prefix
= false; // new prefix means that srp-mdns-proxy received a new prefix from the wire, which it
906 // did not know before.
907 bool on_link_prefix_present
= false;
908 bool something_changed
= assume_changed
;
909 uint64_t now
= ioloop_timenow();
910 bool stale_routers_exist
= false;
912 // No action on interfaces that aren't eligible for routing or that isn't currently active.
913 if (interface
->ineligible
|| interface
->inactive
) {
914 INFO("not evaluating policy on " PUB_S_SRP
" because it's " PUB_S_SRP
, interface
->name
,
915 interface
->ineligible
? "ineligible" : "inactive");
919 // See if we have a prefix from some other router
920 for (router
= interface
->routers
; router
; router
= router
->next
) {
921 icmp_option_t
*option
= router
->options
;
923 if (now
- router
->received_time
> MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE
) {
924 stale_routers_exist
= true;
925 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, router_src_addr_buf
);
926 INFO("Router " PRI_SEGMENTED_IPv6_ADDR_SRP
" is stale by %" PRIu64
" milliseconds",
927 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, router_src_addr_buf
),
928 now
- router
->received_time
);
930 for (i
= 0; i
< router
->num_options
; i
++) {
931 if (option
->type
== icmp_option_prefix_information
) {
932 prefix_information_t
*prefix
= &option
->option
.prefix_information
;
933 if ((prefix
->flags
& ND_OPT_PI_FLAG_ONLINK
) &&
934 ((prefix
->flags
& ND_OPT_PI_FLAG_AUTO
) || (router
->flags
& ND_RA_FLAG_MANAGED
)) &&
935 prefix
->preferred_lifetime
> 0)
937 // If this is a new icmp_message received now and contains PIO.
938 if (router
->new_router
) {
940 router
->new_router
= false; // clear the bit since srp-mdns-proxy already processed it.
943 // Right now all we need is to see if there is an on-link prefix.
944 on_link_prefix_present
= true;
945 SEGMENTED_IPv6_ADDR_GEN_SRP(router
->source
.s6_addr
, __router_src_add_buf
);
946 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, __pio_prefix_buf
);
947 DEBUG("routing_policy_evaluate: router has PIO - ifname: " PUB_S_SRP
", router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
948 ", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
950 SEGMENTED_IPv6_ADDR_PARAM_SRP(router
->source
.s6_addr
, __router_src_add_buf
),
951 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, __pio_prefix_buf
));
959 INFO("policy on " PUB_S_SRP
": " PUB_S_SRP
"stale " /* stale_routers_exist ? */
960 PUB_S_SRP
"disco " /* interface->router_discovery_complete ? */
961 PUB_S_SRP
"present " /* on_link_prefix_present ? */
962 PUB_S_SRP
"advert " /* interface->advertise_ipv6_prefix ? */
963 PUB_S_SRP
"conf " /* interface->on_link_prefix_configured ? */
964 PUB_S_SRP
"new_prefix " /* new_prefix ? */
965 "preferred = %" PRIu32
" valid = %" PRIu32
" deadline = %llu",
966 interface
->name
, stale_routers_exist
? "" : "!", interface
->router_discovery_complete
? "" : "!",
967 on_link_prefix_present
? "" : "!", interface
->advertise_ipv6_prefix
? "" : "!",
968 interface
->on_link_prefix_configured
? "" : "!", new_prefix
? "" : "!",
969 interface
->preferred_lifetime
, interface
->valid_lifetime
, interface
->deprecate_deadline
);
971 // If there are stale routers, start doing router discovery again to see if we can get them to respond.
972 // Also, if we have not yet done router discovery, do it now.
973 if ((!interface
->router_discovery_complete
|| stale_routers_exist
) && !on_link_prefix_present
) {
974 if (!interface
->router_discovery_in_progress
) {
975 // Start router discovery.
976 router_discovery_start(interface
);
978 INFO("routing_policy_evaluate: router discovery in progress");
981 // If we are advertising a prefix and there's another on-link prefix, deprecate the one we are
983 else if (interface
->advertise_ipv6_prefix
&& on_link_prefix_present
) {
984 // If we have been advertising a preferred prefix, deprecate it.
985 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
986 if (interface
->preferred_lifetime
!= 0) {
987 INFO("routing_policy_evaluate: deprecating interface prefix in 30 minutes - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
988 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
989 interface
->preferred_lifetime
= 0;
990 interface
->deprecate_deadline
= now
+ 1800 * 1000;
991 something_changed
= true;
993 INFO("routing_policy_evaluate: prefix deprecating in progress - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
994 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
997 // If there is no on-link prefix and we aren't advertising, or have deprecated, start advertising
998 // again (or for the first time).
999 else if (!on_link_prefix_present
&& interface
->router_discovery_complete
&&
1000 interface
->link
!= NULL
&& interface
->link
->primary
== interface
&&
1001 (!interface
->advertise_ipv6_prefix
|| interface
->deprecate_deadline
!= 0 ||
1002 interface
->preferred_lifetime
== 0)) {
1004 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
);
1005 INFO("routing_policy_evaluate: advertising prefix again - ifname: " PUB_S_SRP
", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
, interface
->name
,
1006 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, __prefix_buf
));
1008 // If we were deprecating, stop.
1009 ioloop_cancel_wake_event(interface
->deconfigure_wakeup
);
1010 interface
->deprecate_deadline
= 0;
1012 // Start advertising immediately, 30 minutes.
1013 interface
->preferred_lifetime
= interface
->valid_lifetime
= 1800;
1015 // If the on-link prefix isn't configured on the interface, do that.
1016 if (!interface
->on_link_prefix_configured
) {
1018 if (!interface
->is_thread
) {
1020 interface_prefix_configure(interface
->ipv6_prefix
, interface
);
1023 INFO("Not setting up " PUB_S_SRP
" because it is the thread interface", interface
->name
);
1027 // Configuring the on-link prefix takes a while, so we want to re-evaluate after it's finished.
1028 interface
->advertise_ipv6_prefix
= true;
1029 something_changed
= true;
1033 // If we've been looking to see if there's an on-link prefix, and we got one from the new router advertisement,
1034 // stop looking for new one.
1036 router_discovery_stop(interface
, now
);
1039 // If anything changed, do an immediate beacon; otherwise wait until the next one.
1040 // Also when something changed, set the number of transmissions back to zero so that
1041 // we send a few initial beacons quickly for reliability.
1042 if (something_changed
) {
1043 INFO("change on " PUB_S_SRP
": " PUB_S_SRP
"disco " PUB_S_SRP
"present " PUB_S_SRP
"advert " PUB_S_SRP
1044 "conf preferred = %" PRIu32
" valid = %" PRIu32
" deadline = %llu",
1045 interface
->name
, interface
->router_discovery_complete
? "" : "!", on_link_prefix_present
? "" : "!",
1046 interface
->advertise_ipv6_prefix
? "" : "!", interface
->on_link_prefix_configured
? "" : "!",
1047 interface
->preferred_lifetime
,
1048 interface
->valid_lifetime
, interface
->deprecate_deadline
);
1049 interface
->num_beacons_sent
= 0;
1050 interface_beacon_schedule(interface
, 0);
1055 start_vicarious_router_discovery_if_appropriate(interface_t
*const interface
)
1057 if (!interface
->advertise_ipv6_prefix
&&
1058 !interface
->vicarious_router_discovery_in_progress
&& !interface
->router_discovery_in_progress
)
1060 if (interface
->vicarious_discovery_complete
== NULL
) {
1061 interface
->vicarious_discovery_complete
= ioloop_wakeup_create();
1063 ioloop_cancel_wake_event(interface
->vicarious_discovery_complete
);
1065 if (interface
->vicarious_discovery_complete
!= NULL
) {
1066 ioloop_add_wake_event(interface
->vicarious_discovery_complete
,
1067 interface
, vicarious_discovery_callback
, NULL
, 20 * 1000);
1068 interface
->vicarious_router_discovery_in_progress
= true;
1070 // In order for vicarious router discovery to be useful, we need all of the routers
1071 // that were present when the first solicit was received to be stale when we give up
1072 // on vicarious discovery. If we got any router advertisements, these will not be
1073 // stale, and that means vicarious discovery succeeded.
1074 make_all_routers_nearly_stale(interface
, ioloop_timenow());
1075 INFO("start_vicarious_router_discovery_if_appropriate: Starting vicarious router discovery on " PUB_S_SRP
,
1081 router_solicit(icmp_message_t
*message
)
1083 interface_t
*iface
, *interface
;
1085 // Further validate the message
1086 if (message
->hop_limit
!= 255 || message
->code
!= 0) {
1087 ERROR("Invalid router solicitation, hop limit = %d, code = %d", message
->hop_limit
, message
->code
);
1089 if (IN6_IS_ADDR_UNSPECIFIED(&message
->source
)) {
1090 icmp_option_t
*option
= message
->options
;
1092 for (i
= 0; i
< message
->num_options
; i
++) {
1093 if (option
->type
== icmp_option_source_link_layer_address
) {
1094 ERROR("source link layer address in router solicitation from unspecified IP address");
1100 // Make sure it's not from this host
1101 for (iface
= interfaces
; iface
; iface
= iface
->next
) {
1102 if (iface
->have_link_layer_address
&& !memcmp(&message
->source
,
1103 &iface
->link_local
, sizeof(message
->source
))) {
1104 INFO("dropping router solicitation sent from this host.");
1109 interface
= message
->interface
;
1111 // Schedule an immediate send, which will be delayed by up to a second.
1112 if (!interface
->ineligible
&& !interface
->inactive
) {
1113 interface_beacon_schedule(interface
, 0);
1116 // When we receive a router solicit, it means that a host is looking for a router. We should
1117 // expect to hear replies if they are multicast. If we hear no replies, it could mean there is
1118 // no on-link prefix. In this case, we restart our own router discovery process. There is no
1119 // need to do this if we are the one advertising a prefix.
1120 start_vicarious_router_discovery_if_appropriate(interface
);
1124 router_advertisement(icmp_message_t
*message
)
1127 icmp_message_t
*router
, **rp
;
1128 if (message
->hop_limit
!= 255 || message
->code
!= 0 || !IN6_IS_ADDR_LINKLOCAL(&message
->source
)) {
1129 ERROR("Invalid router advertisement, hop limit = %d, code = %d", message
->hop_limit
, message
->code
);
1130 icmp_message_free(message
);
1133 for (iface
= interfaces
; iface
!= NULL
; iface
= iface
->next
) {
1134 if (iface
->have_link_layer_address
&& !memcmp(&message
->source
,
1135 &iface
->link_local
, sizeof(message
->source
))) {
1136 INFO("dropping router advertisement sent from this host.");
1137 icmp_message_free(message
);
1142 // See if we've had other advertisements from this router.
1143 for (rp
= &message
->interface
->routers
; *rp
!= NULL
; rp
= &(*rp
)->next
) {
1145 if (!memcmp(&router
->source
, &message
->source
, sizeof(message
->source
))) {
1146 message
->next
= router
->next
;
1148 icmp_message_free(router
);
1157 // Something may have changed, so do a policy recalculation for this interface
1158 routing_policy_evaluate(message
->interface
, false);
1162 icmp_callback(io_t
*NONNULL io
, void *__unused context
)
1165 uint8_t icmp_buf
[1500];
1166 unsigned offset
= 0, length
= 0;
1167 uint32_t reserved32
;
1170 interface_t
*interface
;
1173 rv
= ioloop_recvmsg(io
->fd
, &icmp_buf
[0], sizeof(icmp_buf
), &ifindex
, &hop_limit
, &src
, &dest
);
1175 ERROR("icmp_callback: can't read ICMP message: " PUB_S_SRP
, strerror(errno
));
1179 icmp_message_t
*message
= calloc(1, sizeof(*message
));
1180 if (message
== NULL
) {
1181 ERROR("Unable to allocate icmp_message_t for parsing");
1185 message
->source
= src
.sin6
.sin6_addr
;
1186 message
->destination
= dest
.sin6
.sin6_addr
;
1187 message
->hop_limit
= hop_limit
;
1188 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1189 if (interface
->index
== ifindex
) {
1190 message
->interface
= interface
;
1194 message
->received_time
= ioloop_timenow();
1195 message
->received_time_already_adjusted
= false;
1196 message
->new_router
= true;
1198 if (message
->interface
== NULL
) {
1199 SEGMENTED_IPv6_ADDR_GEN_SRP(message
->source
.s6_addr
, src_buf
);
1200 SEGMENTED_IPv6_ADDR_GEN_SRP(message
->destination
.s6_addr
, dst_buf
);
1201 INFO("ICMP message type %d from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
1202 " on interface index %d, which isn't listed.",
1203 icmp_buf
[0], SEGMENTED_IPv6_ADDR_PARAM_SRP(message
->source
.s6_addr
, src_buf
),
1204 SEGMENTED_IPv6_ADDR_PARAM_SRP(message
->destination
.s6_addr
, dst_buf
), ifindex
);
1205 icmp_message_free(message
);
1209 length
= (unsigned)rv
;
1210 if (length
< sizeof (struct icmp6_hdr
)) {
1211 ERROR("Short ICMP message: length %zd is shorter than ICMP header length %zd", rv
, sizeof(struct icmp6_hdr
));
1212 icmp_message_free(message
);
1216 // The increasingly innaccurately named dns parse functions will work fine for this.
1217 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->type
)) {
1220 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->code
)) {
1223 // XXX check the checksum
1224 if (!dns_u16_parse(icmp_buf
, length
, &offset
, &message
->checksum
)) {
1227 switch(message
->type
) {
1228 case icmp_type_router_advertisement
:
1229 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->cur_hop_limit
)) {
1232 if (!dns_u8_parse(icmp_buf
, length
, &offset
, &message
->flags
)) {
1235 if (!dns_u16_parse(icmp_buf
, length
, &offset
, &message
->router_lifetime
)) {
1238 if (!dns_u32_parse(icmp_buf
, length
, &offset
, &message
->reachable_time
)) {
1241 if (!dns_u32_parse(icmp_buf
, length
, &offset
, &message
->retransmission_timer
)) {
1245 if (!icmp_message_parse_options(message
, icmp_buf
, length
, &offset
)) {
1248 icmp_message_dump(message
, &message
->source
, &message
->destination
);
1249 router_advertisement(message
);
1250 // router_advertisement() is ressponsible for freeing the messaage if it doesn't need it.
1254 case icmp_type_router_solicitation
:
1255 if (!dns_u32_parse(icmp_buf
, length
, &offset
, &reserved32
)) {
1258 if (!icmp_message_parse_options(message
, icmp_buf
, length
, &offset
)) {
1261 icmp_message_dump(message
, &message
->source
, &message
->destination
);
1262 router_solicit(message
);
1264 case icmp_type_neighbor_advertisement
:
1265 case icmp_type_neighbor_solicitation
:
1266 case icmp_type_echo_request
:
1267 case icmp_type_echo_reply
:
1268 case icmp_type_redirect
:
1273 icmp_message_free(message
);
1277 #ifdef MONITOR_ROUTING_SOCKET
1279 route_message(io_t
*__unused rt
, route_message_t
*message
)
1283 switch(message
->route
.rtm_type
) {
1284 // When an interface goes up, or when an address is added, we get one of these.
1286 INFO("Message length %d, version %d, type RTM_NEWADDR, index %d",
1287 message
->len
, message
->route
.rtm_version
, message
->address
.ifam_index
);
1288 // ifa_msghdr followed by zero or more addresses
1289 // Addresses start on 32-bit boundaries and are sockaddrs with sa_len indicating the size.
1290 addr
= (addr_t
*)((&message
->address
) + 1);
1292 // When an interface goes down, we may get one of these. Also when an address is deleted for some reason.
1294 INFO("Message length %d, version %d, type RTM_DELADDR, index %d",
1295 message
->len
, message
->route
.rtm_version
, message
->address
.ifam_index
);
1296 // ifa_msghdr followed by zero or more addresses
1297 addr
= (addr_t
*)((&message
->address
) + 1);
1299 // When an interface goes up or down, we get one of these.
1301 INFO("Message length %d, version %d, type RTM_IFINFO, index %d",
1302 message
->len
, message
->route
.rtm_version
, message
->interface
.ifm_index
);
1303 // if_msghdr followed by zero or more addresses
1304 addr
= (addr_t
*)((&message
->interface
) + 1);
1307 INFO("Message length %d, version %d, type RTM_IFINFO2, index %d",
1308 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1309 addr
= (addr_t
*)((&message
->if2
) + 1);
1312 INFO("Message length %d, version %d, type RTM_ADD, index %d",
1313 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1314 addr
= (addr_t
*)((&message
->if2
) + 1);
1317 INFO("Message length %d, version %d, type RTM_DELETE, index %d",
1318 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1319 addr
= (addr_t
*)((&message
->if2
) + 1);
1322 INFO("Message length %d, version %d, type RTM_CHANGE, index %d",
1323 message
->len
, message
->route
.rtm_version
, message
->if2
.ifm_index
);
1324 addr
= (addr_t
*)((&message
->if2
) + 1);
1327 INFO("Message length %d, version %d, type %d", message
->len
, message
->route
.rtm_version
,
1328 message
->route
.rtm_type
);
1335 route_callback(io_t
*NONNULL io
, void *__unused context
)
1338 route_message_t message
;
1340 rv
= read(io
->fd
, &message
, sizeof message
);
1342 ERROR("route_callback: read returned " PUB_S_SRP
, strerror(errno
));
1345 } else if (rv
== 0) {
1346 ERROR("route_callback: read returned 0");
1350 // Process the message.
1351 route_message(io
, &message
);
1357 route_entry(struct rt_msghdr2
*route
)
1366 #define NUM_SYSCTL_ARGS 6
1367 int sysctl_args
[NUM_SYSCTL_ARGS
];
1368 char *table
, *next_route
, *end
;
1369 struct rt_msghdr2
*route
;
1372 sysctl_args
[0] = CTL_NET
;
1373 sysctl_args
[1] = PF_ROUTE
;
1376 sysctl_args
[4] = NET_RT_DUMP2
;
1379 rv
= sysctl(sysctl_args
, NUM_SYSCTL_ARGS
, NULL
, &table_size
, NULL
, 0);
1381 ERROR("route_fetch: sysctl failed getting routing table dump estimate: " PUB_S_SRP
, strerror(errno
));
1385 table
= malloc(table_size
);
1386 if (table
== NULL
) {
1387 ERROR("No memory for routing table of size %zu", table_size
);
1391 rv
= sysctl(sysctl_args
, NUM_SYSCTL_ARGS
, table
, &table_size
, NULL
, 0);
1393 ERROR("route_fetch: sysctl failed getting routing table dump: " PUB_S_SRP
, strerror(errno
));
1397 end
= table
+ table_size
;
1398 for (next_route
= table
; next_route
< end
; next_route
= next_route
+ route
->rtm_msglen
) {
1399 route
= (struct rt_msghdr2
*)next_route
;
1400 if (route
->rtm_msglen
+ next_route
> end
) {
1401 INFO("Bogus routing table--last route goes past end of buffer.");
1409 start_route_listener(void)
1411 int sock
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
);
1413 ERROR("Unable to listen for link status change events: " PUB_S_SRP
, strerror(errno
));
1417 io_t
*io
= ioloop_file_descriptor_create(sock
, NULL
, NULL
);
1419 ERROR("No memory for route I/O structure.");
1425 static uint8_t subscriptions
[] = { RTM_NEWADDR
, RTM_DELADDR
, RTM_IFINFO
, RTM_IFINFO2
};
1426 if (setsockopt(routefd
, PF_ROUTE
, RO_MSGFILTER
, &subscriptions
, (socklen_t
)sizeof(subscriptions
)) < 0) {
1427 ERROR("Unable to set routing socket subscriptions.");
1431 ioloop_add_reader(io
, route_callback
);
1436 #endif // MONITOR_ROUTING_SOCKET
1438 #if defined(USE_IPCONFIGURATION_SERVICE)
1440 dict_add_string_as_array(CFMutableDictionaryRef dict
, CFStringRef prop_name
, const char * str
)
1443 CFStringRef prop_val
;
1448 prop_val
= CFStringCreateWithCString(NULL
, str
, kCFStringEncodingUTF8
);
1449 array
= CFArrayCreate(NULL
, (const void **)&prop_val
, 1, &kCFTypeArrayCallBacks
);
1450 CFRelease(prop_val
);
1451 CFDictionarySetValue(dict
, prop_name
, array
);
1457 dict_add_int_as_array(CFMutableDictionaryRef dict
, CFStringRef prop_name
,
1463 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &int_val
);
1464 array
= CFArrayCreate(NULL
, (const void **)&num
, 1, &kCFTypeArrayCallBacks
);
1466 CFDictionarySetValue(dict
, prop_name
, array
);
1471 static CFDictionaryRef
1472 ipconfig_options_dict_create(CFDictionaryRef config_dict
)
1474 return CFDictionaryCreate(NULL
, (const void **)&kIPConfigurationServiceOptionIPv6Entity
,
1475 (const void **)&config_dict
, 1, &kCFTypeDictionaryKeyCallBacks
,
1476 &kCFTypeDictionaryValueCallBacks
);
1480 ipconfig_service_changed(interface_t
* interface
)
1482 CFDictionaryRef service_info
;
1484 if (interface
->ip_configuration_service
== NULL
) {
1485 INFO("ipconfig_service_changed: ip_configuration_service is NULL");
1488 service_info
= IPConfigurationServiceCopyInformation(interface
->ip_configuration_service
);
1489 if (service_info
== NULL
) {
1490 INFO("ipconfig_service_changed: IPConfigurationService on " PUB_S_SRP
" is incomplete", interface
->name
);
1493 INFO("ipconfig_service_changed: IPConfigurationService on " PUB_S_SRP
" is ready", interface
->name
);
1494 CFRelease(service_info
);
1496 // Now that the prefix is configured on the interface, we can start advertising it.
1497 interface
->on_link_prefix_configured
= true;
1498 routing_policy_evaluate(interface
, true);
1506 ipconfig_service_callback(SCDynamicStoreRef __unused session
, CFArrayRef __unused changes
,
1509 interface_t
* interface
= (interface_t
*)info
;
1511 ipconfig_service_changed(interface
);
1516 monitor_ipconfig_service(interface_t
* interface
)
1518 SCDynamicStoreContext context
= {
1523 .copyDescription
= NULL
1526 SCDynamicStoreRef store
;
1527 CFStringRef store_key
;
1529 if (interface
->ip_configuration_store
!= NULL
) {
1530 INFO("Releasing old SCDynamicStore object for " PUB_S_SRP
, interface
->name
);
1531 SCDynamicStoreSetDispatchQueue(interface
->ip_configuration_store
, NULL
);
1532 CFRelease(interface
->ip_configuration_store
);
1533 interface
->ip_configuration_store
= NULL
;
1536 #define OUR_IDENTIFIER CFSTR("ThreadBorderRouter")
1537 context
.info
= interface
;
1538 store
= SCDynamicStoreCreate(NULL
, OUR_IDENTIFIER
,
1539 ipconfig_service_callback
, &context
);
1540 store_key
= IPConfigurationServiceGetNotificationKey(interface
->ip_configuration_service
);
1541 keys
= CFArrayCreate(NULL
, (const void * *)&store_key
,
1543 &kCFTypeArrayCallBacks
);
1544 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
1547 /* avoid race with being notified */
1548 ipconfig_service_changed(interface
);
1549 SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue());
1550 interface
->ip_configuration_store
= (void *)store
;
1554 start_ipconfig_service(interface_t
*interface
, const char *ip6addr_str
)
1556 CFMutableDictionaryRef config_dict
;
1557 CFStringRef interface_name
;
1558 CFDictionaryRef options
;
1560 if (interface
->ip_configuration_service
!= NULL
) {
1561 INFO("start_ipconfig_service: releasing old IPConfigurationService object for " PUB_S_SRP
, interface
->name
);
1562 CFRelease(interface
->ip_configuration_service
);
1563 interface
->ip_configuration_service
= NULL
;
1566 // Create an IPv6 entity dictionary with ConfigMethod, Addresses, and PrefixLength properties
1567 config_dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1568 CFDictionarySetValue(config_dict
, kSCPropNetIPv6ConfigMethod
, kSCValNetIPv6ConfigMethodManual
);
1569 #define PREFIX_LENGTH 64
1570 dict_add_string_as_array(config_dict
, kSCPropNetIPv6Addresses
, ip6addr_str
);
1571 dict_add_int_as_array(config_dict
, kSCPropNetIPv6PrefixLength
, PREFIX_LENGTH
);
1572 options
= ipconfig_options_dict_create(config_dict
);
1573 CFRelease(config_dict
);
1574 interface_name
= CFStringCreateWithCString(NULL
, interface
->name
, kCFStringEncodingUTF8
);
1575 interface
->ip_configuration_service
= IPConfigurationServiceCreate(interface_name
, options
);
1576 CFRelease(interface_name
);
1578 if (interface
->ip_configuration_service
== NULL
) {
1579 ERROR("start_ipconfig_service: IPConfigurationServiceCreate on " PUB_S_SRP
" failed", interface
->name
);
1582 monitor_ipconfig_service(interface
);
1583 struct in6_addr ip6addr
;
1584 int ret
= inet_pton(AF_INET6
, ip6addr_str
, ip6addr
.s6_addr
);
1586 SEGMENTED_IPv6_ADDR_GEN_SRP(ip6addr
.s6_addr
, ip6addr_buf
);
1587 INFO("start_ipconfig_service: IPConfigurationServiceCreate on " PRI_S_SRP
"/" PRI_SEGMENTED_IPv6_ADDR_SRP
1588 " succeeded", interface
->name
, SEGMENTED_IPv6_ADDR_PARAM_SRP(ip6addr
.s6_addr
, ip6addr_buf
));
1591 return (interface
->ip_configuration_service
!= NULL
);
1594 #elif defined(CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG)
1596 link_route_done(void *context
, int status
, const char *error
)
1598 interface_t
*interface
= context
;
1600 if (error
!= NULL
) {
1601 ERROR("link_route_done on " PUB_S_SRP
": " PUB_S_SRP
, interface
->name
, error
);
1603 INFO("link_route_done on " PUB_S_SRP
": %d.", interface
->name
, status
);
1605 ioloop_subproc_release(link_route_adder_process
);
1606 // Now that the on-link prefix is configured, time for a policy re-evaluation.
1607 interface
->on_link_prefix_configured
= true;
1608 routing_policy_evaluate(interface
, true);
1613 interface_prefix_configure(struct in6_addr prefix
, interface_t
*interface
)
1617 sock
= socket(PF_INET6
, SOCK_DGRAM
, 0);
1619 ERROR("interface_prefix_configure: socket(PF_INET6, SOCK_DGRAM, 0) failed " PUB_S_SRP
": " PUB_S_SRP
,
1620 interface
->name
, strerror(errno
));
1623 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
1624 struct in6_addr interface_address
= prefix
;
1625 char addrbuf
[INET6_ADDRSTRLEN
];
1626 interface_address
.s6_addr
[15] = 1;
1627 inet_ntop(AF_INET6
, &interface_address
, addrbuf
, INET6_ADDRSTRLEN
);
1628 #if defined (USE_IPCONFIGURATION_SERVICE)
1629 if (!start_ipconfig_service(interface
, addrbuf
)) {
1633 #elif defined(CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG)
1634 char *args
[] = { "set", interface
->name
, "MANUAL-V6", addrbuf
, "64" };
1636 INFO("interface_prefix_configure: /sbin/ipconfig " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" "
1637 PUB_S_SRP
, args
[0], args
[1], args
[2], args
[3], args
[4]);
1638 link_route_adder_process
= ioloop_subproc("/usr/sbin/ipconfig", args
, 5, link_route_done
, interface
, NULL
);
1639 if (link_route_adder_process
== NULL
) {
1640 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address
.s6_addr
, if_addr_buf
);
1641 ERROR("interface_prefix_configure: unable to set interface address for " PUB_S_SRP
" to "
1642 PRI_SEGMENTED_IPv6_ADDR_SRP
".", interface
->name
,
1643 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address
.s6_addr
, if_addr_buf
));
1646 struct in6_aliasreq alias_request
;
1647 memset(&alias_request
, 0, sizeof(alias_request
));
1648 strlcpy(alias_request
.ifra_name
, interface
->name
, IFNAMSIZ
);
1649 alias_request
.ifra_addr
.sin6_family
= AF_INET6
;
1650 alias_request
.ifra_addr
.sin6_len
= sizeof(alias_request
.ifra_addr
);
1651 memcpy(&alias_request
.ifra_addr
.sin6_addr
, &interface_address
, sizeof(alias_request
.ifra_addr
.sin6_addr
));
1652 alias_request
.ifra_prefixmask
.sin6_len
= sizeof(alias_request
.ifra_addr
);
1653 alias_request
.ifra_prefixmask
.sin6_family
= AF_INET6
;
1654 memset(&alias_request
.ifra_prefixmask
.sin6_addr
, 0xff, 8); // /64.
1655 alias_request
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
; // seconds, I hope?
1656 alias_request
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
; // seconds, I hope?
1657 ret
= ioctl(sock
, SIOCAIFADDR_IN6
, &alias_request
);
1659 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address
.s6_addr
, if_addr_buf
);
1660 ERROR("interface_prefix_configure: can't configure static address " PRI_SEGMENTED_IPv6_ADDR_SRP
" on " PUB_S_SRP
1661 ": " PUB_S_SRP
, SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address
.s6_addr
, if_addr_buf
), interface
->name
,
1664 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address
.s6_addr
, if_addr_buf
);
1665 INFO("interface_prefix_configure: added address " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PUB_S_SRP
,
1666 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address
.s6_addr
, if_addr_buf
), interface
->name
);
1668 #endif // CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG
1671 #endif // CONFIGURE_STATIC_INTERFACE_ADDRESSES
1674 #ifdef USE_SYSCTL_COMMMAND_TO_ENABLE_FORWARDING
1676 thread_forwarding_done(void *__unused context
, int status
, const char *error
)
1678 if (error
!= NULL
) {
1679 ERROR("thread_forwarding_done: " PUB_S_SRP
, error
);
1681 INFO("thread_forwarding_done: %d.", status
);
1683 ioloop_subproc_release(thread_forwarding_setter_process
);
1687 set_thread_forwarding(void)
1689 char *args
[] = { "-w", "net.inet6.ip6.forwarding=1" };
1691 INFO("/usr/sbin/sysctl " PUB_S_SRP
" " PUB_S_SRP
, args
[0], args
[1]);
1692 thread_forwarding_setter_process
= ioloop_subproc("/usr/sbin/sysctl", args
, 2, thread_forwarding_done
,
1694 if (thread_forwarding_setter_process
== NULL
) {
1695 ERROR("Unable to set thread forwarding enabled.");
1702 set_thread_forwarding(void)
1705 int ret
= sysctlbyname("net.inet6.ip6.forwarding", NULL
, 0, &wun
, sizeof(wun
));
1707 ERROR("set_thread_forwarding: " PUB_S_SRP
, strerror(errno
));
1709 INFO("Enabled IPv6 forwarding.");
1712 #endif // USE_SYSCTL_COMMMAND_TO_ENABLE_FORWARDING
1714 #ifdef NEED_THREAD_RTI_SETTER
1716 thread_rti_done(void *__unused context
, int status
, const char *error
)
1718 if (error
!= NULL
) {
1719 ERROR("thread_rti_done: " PUB_S_SRP
, error
);
1721 INFO("thread_rti_done: %d.", status
);
1723 ioloop_subproc_release(thread_rti_setter_process
);
1727 set_thread_rti(void)
1729 char *args
[] = { "-w", "net.inet6.icmp6.nd6_process_rti=1" };
1730 thread_rti_setter_process
= ioloop_subproc("/usr/sbin/sysctl", args
, 2, thread_rti_done
,
1732 if (thread_rti_setter_process
== NULL
) {
1733 ERROR("Unable to set thread rti enabled.");
1738 #if TARGET_OS_TV && !defined(RA_TESTER)
1739 #ifdef ADD_PREFIX_WITH_WPANCTL
1741 thread_prefix_done(void *__unused context
, int status
, const char *error
)
1743 if (error
!= NULL
) {
1744 ERROR("thread_prefix_done: " PUB_S_SRP
, error
);
1746 interface_t
*interface
;
1748 INFO("thread_prefix_done: %d.", status
);
1749 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1750 if (!interface
->inactive
) {
1751 interface_beacon_schedule(interface
, 0);
1755 ioloop_subproc_release(thread_prefix_adder_process
);
1760 cti_add_prefix_callback(void *__unused context
, cti_status_t status
)
1762 interface_t
*interface
;
1763 INFO("cti_add_prefix_callback: %d", status
);
1764 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1765 if (!interface
->inactive
) {
1766 interface_beacon_schedule(interface
, 0);
1771 static thread_prefix_t
*
1772 get_advertised_thread_prefix(void)
1774 if (published_thread_prefix
!= NULL
) {
1775 return published_thread_prefix
;
1777 return adopted_thread_prefix
;
1783 set_thread_prefix(void)
1785 char addrbuf
[INET6_ADDRSTRLEN
];
1786 thread_prefix_t
*advertised_thread_prefix
= get_advertised_thread_prefix();
1787 if (advertised_thread_prefix
== NULL
) {
1788 ERROR("set_thread_prefix: no advertised thread prefix.");
1791 SEGMENTED_IPv6_ADDR_GEN_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
);
1792 inet_ntop(AF_INET6
, &advertised_thread_prefix
->prefix
, addrbuf
, sizeof addrbuf
);
1793 #ifdef ADD_PREFIX_WITH_WPANCTL
1794 char *args
[] = { "add-prefix", "--stable", "--preferred", "--slaac", "--default-route", "--on-mesh", addrbuf
};
1795 INFO("/usr/local/bin/wpanctl " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" " PUB_S_SRP
" "
1796 PRI_SEGMENTED_IPv6_ADDR_SRP
, args
[0], args
[1], args
[2], args
[3], args
[4], args
[5],
1797 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
));
1798 thread_prefix_adder_process
= ioloop_subproc("/usr/local/bin/wpanctl", args
, 7, thread_prefix_done
,
1800 if (thread_prefix_adder_process
== NULL
) {
1801 ERROR("Unable to add thread interface prefix.");
1804 INFO("add_prefix(true, true, true, true, " PRI_SEGMENTED_IPv6_ADDR_SRP
")",
1805 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
));
1806 int status
= cti_add_prefix(NULL
, cti_add_prefix_callback
, dispatch_get_main_queue(),
1807 &advertised_thread_prefix
->prefix
, advertised_thread_prefix
->prefix_len
,
1808 true, true, true, true);
1810 ERROR("Unable to add thread interface prefix.");
1814 #endif // TARGET_OS_TV && !RA_TESTER
1817 router_advertisement_send(interface_t
*interface
)
1820 dns_towire_state_t towire
;
1822 // Thread blocks RAs so no point sending them.
1823 if (interface
->inactive
1825 || interface
->is_thread
1831 #define MAX_ICMP_MESSAGE 1280
1832 message
= malloc(MAX_ICMP_MESSAGE
);
1833 if (message
== NULL
) {
1834 ERROR("Unable to construct ICMP Router Advertisement: no memory");
1838 // Construct the ICMP header and options for each interface.
1839 memset(&towire
, 0, sizeof towire
);
1841 towire
.lim
= message
+ MAX_ICMP_MESSAGE
;
1843 // Construct the ICMP header.
1844 // We use the DNS message construction functions because it's easy; probably should just make
1845 // the towire functions more generic.
1846 dns_u8_to_wire(&towire
, ND_ROUTER_ADVERT
); // icmp6_type
1847 dns_u8_to_wire(&towire
, 0); // icmp6_code
1848 dns_u16_to_wire(&towire
, 0); // The kernel computes the checksum (we don't technically have it).
1849 dns_u8_to_wire(&towire
, 0); // Hop limit, we don't set.
1850 dns_u8_to_wire(&towire
, 0); // Flags. We don't offer DHCP, so We set neither the M nor the O bit.
1851 // We are not a home agent, so no H bit. Lifetime is 0, so Prf is 0.
1852 #ifdef ROUTER_LIFETIME_HACK
1853 dns_u16_to_wire(&towire
, 1800); // Router lifetime, hacked. This shouldn't ever be enabled.
1856 // Advertise a default route on the simulated thread network
1857 if (!strcmp(interface
->name
, thread_interface_name
)) {
1858 dns_u16_to_wire(&towire
, 1800); // Router lifetime for default route
1861 dns_u16_to_wire(&towire
, 0); // Router lifetime for non-default default route(s).
1865 #endif // ROUTER_LIFETIME_HACK
1866 dns_u32_to_wire(&towire
, 0); // Reachable time for NUD, we have no opinion on this.
1867 dns_u32_to_wire(&towire
, 0); // Retransmission timer, again we have no opinion.
1869 // Send Source link-layer address option
1870 if (interface
->have_link_layer_address
) {
1871 dns_u8_to_wire(&towire
, ND_OPT_SOURCE_LINKADDR
);
1872 dns_u8_to_wire(&towire
, 1); // length / 8
1873 dns_rdata_raw_data_to_wire(&towire
, &interface
->link_layer
, sizeof(interface
->link_layer
));
1874 INFO("Advertising source lladdr " PRI_MAC_ADDR_SRP
" on " PUB_S_SRP
, MAC_ADDR_PARAM_SRP(interface
->link_layer
),
1879 // Send MTU of 1280 for Thread?
1880 if (interface
->is_thread
) {
1881 dns_u8_to_wire(&towire
, ND_OPT_MTU
);
1882 dns_u8_to_wire(&towire
, 1); // length / 8
1883 dns_u32_to_wire(&towire
, 1280);
1884 INFO("Advertising MTU of 1280 on " PUB_S_SRP
, interface
->name
);
1888 // Send Prefix Information option if there's no IPv6 on the link.
1889 if (interface
->advertise_ipv6_prefix
) {
1890 dns_u8_to_wire(&towire
, ND_OPT_PREFIX_INFORMATION
);
1891 dns_u8_to_wire(&towire
, 4); // length / 8
1892 dns_u8_to_wire(&towire
, 64); // On-link prefix is always 64 bits
1893 dns_u8_to_wire(&towire
, ND_OPT_PI_FLAG_ONLINK
| ND_OPT_PI_FLAG_AUTO
); // On link, autoconfig
1894 dns_u32_to_wire(&towire
, interface
->valid_lifetime
);
1895 dns_u32_to_wire(&towire
, interface
->preferred_lifetime
);
1896 dns_u32_to_wire(&towire
, 0); // Reserved
1897 dns_rdata_raw_data_to_wire(&towire
, &interface
->ipv6_prefix
, sizeof interface
->ipv6_prefix
);
1898 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
);
1899 INFO("Advertising on-link prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" on " PUB_S_SRP
,
1900 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
), interface
->name
);
1903 #ifndef ND_OPT_ROUTE_INFORMATION
1904 #define ND_OPT_ROUTE_INFORMATION 24
1906 // In principle we can either send routes to links that are reachable by this router,
1907 // or just advertise a router to the entire ULA /48. In theory it doesn't matter
1908 // which we do; if we support HNCP at some point we probably need to be specific, but
1909 // for now being general is fine because we have no way to share a ULA.
1910 // Unfortunately, some RIO implementations do not work with specific routes, so for now
1911 // We are doing it the easy way and just advertising the /48.
1912 #define SEND_INTERFACE_SPECIFIC_RIOS 1
1913 #ifdef SEND_INTERFACE_SPECIFIC_RIOS
1915 // If neither ROUTE_BETWEEN_NON_THREAD_LINKS nor RA_TESTER are defined, then we never want to
1916 // send an RIO other than for the thread network prefix.
1917 #if defined (ROUTE_BETWEEN_NON_THREAD_LINKS) || defined(RA_TESTER)
1918 interface_t
*ifroute
;
1919 // Send Route Information option for other interfaces.
1920 for (ifroute
= interfaces
; ifroute
; ifroute
= ifroute
->next
) {
1921 if (ifroute
->inactive
) {
1926 partition_can_provide_routing
&&
1928 ifroute
->advertise_ipv6_prefix
&&
1929 #ifdef SEND_ON_LINK_ROUTE
1930 // In theory we don't want to send RIO for the on-link prefix, but there's this bug, see.
1933 ifroute
!= interface
&&
1936 // For the RA tester, we don't need to send an RIO to the thread network because we're the
1937 // default router for that network.
1938 strcmp(interface
->name
, thread_interface_name
)
1944 dns_u8_to_wire(&towire
, ND_OPT_ROUTE_INFORMATION
);
1945 dns_u8_to_wire(&towire
, 2); // length / 8
1946 dns_u8_to_wire(&towire
, 64); // Interface prefixes are always 64 bits
1947 dns_u8_to_wire(&towire
, 0); // There's no reason at present to prefer one Thread BR over another
1948 dns_u32_to_wire(&towire
, 1800); // Route lifetime 1800 seconds (30 minutes)
1949 dns_rdata_raw_data_to_wire(&towire
, &ifroute
->ipv6_prefix
, 8); // /64 requires 8 bytes.
1950 SEGMENTED_IPv6_ADDR_GEN_SRP(ifroute
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
);
1951 INFO("Sending route to " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%" PUB_S_SRP
" on " PUB_S_SRP
,
1952 SEGMENTED_IPv6_ADDR_PARAM_SRP(ifroute
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
),
1953 ifroute
->name
, interface
->name
);
1956 #endif // ROUTE_BETWEEN_NON_THREAD_LINKS || RA_TESTER
1959 // Send route information option for thread prefix
1960 thread_prefix_t
*advertised_thread_prefix
= get_advertised_thread_prefix();
1961 if (advertised_thread_prefix
!= NULL
) {
1962 dns_u8_to_wire(&towire
, ND_OPT_ROUTE_INFORMATION
);
1963 dns_u8_to_wire(&towire
, 2); // length / 8
1964 dns_u8_to_wire(&towire
, 64); // Interface prefixes are always 64 bits
1965 dns_u8_to_wire(&towire
, 0); // There's no reason at present to prefer one Thread BR over another
1966 dns_u32_to_wire(&towire
, 1800); // Route lifetime 1800 seconds (30 minutes)
1967 dns_rdata_raw_data_to_wire(&towire
, &advertised_thread_prefix
->prefix
, 8); // /64 requires 8 bytes.
1968 SEGMENTED_IPv6_ADDR_GEN_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
);
1969 INFO("Sending route to " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%" PUB_S_SRP
" on " PUB_S_SRP
,
1970 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix
->prefix
.s6_addr
, thread_prefix_buf
),
1971 thread_interface_name
, interface
->name
);
1975 #ifndef SKIP_SLASH_48
1976 dns_u8_to_wire(&towire
, ND_OPT_ROUTE_INFORMATION
);
1977 dns_u8_to_wire(&towire
, 3); // length / 8
1978 dns_u8_to_wire(&towire
, 48); // ULA prefixes are always 48 bits
1979 dns_u8_to_wire(&towire
, 0); // There's no reason at present to prefer one Thread BR over another
1980 dns_u32_to_wire(&towire
, 1800); // Route lifetime 1800 seconds (30 minutes)
1981 dns_rdata_raw_data_to_wire(&towire
, &ula_prefix
, 16); // /48 requires 16 bytes
1982 #endif // SKIP_SLASH_48
1983 #endif // SEND_INTERFACE_SPECIFIC_RIOS
1986 ERROR("No space in ICMP output buffer for " PUB_S_SRP
" at route.c:%d", interface
->name
, towire
.line
);
1989 icmp_send(message
, towire
.p
- message
, interface
, &in6addr_linklocal_allnodes
);
1995 router_solicit_send(interface_t
*interface
)
1998 dns_towire_state_t towire
;
2000 // Thread blocks RSs so no point sending them.
2001 if (interface
->inactive
2003 || interface
->is_thread
2009 #define MAX_ICMP_MESSAGE 1280
2010 message
= malloc(MAX_ICMP_MESSAGE
);
2011 if (message
== NULL
) {
2012 ERROR("Unable to construct ICMP Router Advertisement: no memory");
2016 // Construct the ICMP header and options for each interface.
2017 memset(&towire
, 0, sizeof towire
);
2019 towire
.lim
= message
+ MAX_ICMP_MESSAGE
;
2021 // Construct the ICMP header.
2022 // We use the DNS message construction functions because it's easy; probably should just make
2023 // the towire functions more generic.
2024 dns_u8_to_wire(&towire
, ND_ROUTER_SOLICIT
); // icmp6_type
2025 dns_u8_to_wire(&towire
, 0); // icmp6_code
2026 dns_u16_to_wire(&towire
, 0); // The kernel computes the checksum (we don't technically have it).
2027 dns_u32_to_wire(&towire
, 0); // Reserved32
2029 // Send Source link-layer address option
2030 if (interface
->have_link_layer_address
) {
2031 dns_u8_to_wire(&towire
, ND_OPT_SOURCE_LINKADDR
);
2032 dns_u8_to_wire(&towire
, 1); // length / 8
2033 dns_rdata_raw_data_to_wire(&towire
, &interface
->link_layer
, sizeof(interface
->link_layer
));
2037 ERROR("No space in ICMP output buffer for " PUB_S_SRP
" at route.c:%d", interface
->name
, towire
.line
);
2039 icmp_send(message
, towire
.p
- message
, interface
, &in6addr_linklocal_allrouters
);
2045 icmp_send(uint8_t *message
, size_t length
, interface_t
*interface
, const struct in6_addr
*destination
)
2048 socklen_t cmsg_length
= CMSG_SPACE(sizeof(struct in6_pktinfo
)) + CMSG_SPACE(sizeof (int));
2049 uint8_t *cmsg_buffer
;
2050 struct msghdr msg_header
;
2051 struct cmsghdr
*cmsg_pointer
;
2052 struct in6_pktinfo
*packet_info
;
2053 int hop_limit
= 255;
2055 struct sockaddr_in6 dest
;
2057 // Make space for the control message buffer.
2058 cmsg_buffer
= malloc(cmsg_length
);
2059 if (cmsg_buffer
== NULL
) {
2060 ERROR("Unable to construct ICMP Router Advertisement: no memory");
2065 memset(&dest
, 0, sizeof(dest
));
2066 dest
.sin6_family
= AF_INET6
;
2067 dest
.sin6_scope_id
= interface
->index
;
2068 dest
.sin6_len
= sizeof(dest
);
2069 msg_header
.msg_namelen
= sizeof(dest
);
2070 dest
.sin6_addr
= *destination
;
2072 msg_header
.msg_name
= &dest
;
2073 iov
.iov_base
= message
;
2074 iov
.iov_len
= length
;
2075 msg_header
.msg_iov
= &iov
;
2076 msg_header
.msg_iovlen
= 1;
2077 msg_header
.msg_control
= cmsg_buffer
;
2078 msg_header
.msg_controllen
= cmsg_length
;
2080 // Specify the interface
2081 cmsg_pointer
= CMSG_FIRSTHDR(&msg_header
);
2082 cmsg_pointer
->cmsg_level
= IPPROTO_IPV6
;
2083 cmsg_pointer
->cmsg_type
= IPV6_PKTINFO
;
2084 cmsg_pointer
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
2085 packet_info
= (struct in6_pktinfo
*)CMSG_DATA(cmsg_pointer
);
2086 memset(packet_info
, 0, sizeof(*packet_info
));
2087 packet_info
->ipi6_ifindex
= interface
->index
;
2089 // Router advertisements and solicitations have a hop limit of 255
2090 cmsg_pointer
= CMSG_NXTHDR(&msg_header
, cmsg_pointer
);
2091 cmsg_pointer
->cmsg_level
= IPPROTO_IPV6
;
2092 cmsg_pointer
->cmsg_type
= IPV6_HOPLIMIT
;
2093 cmsg_pointer
->cmsg_len
= CMSG_LEN(sizeof(int));
2094 memcpy(CMSG_DATA(cmsg_pointer
), &hop_limit
, sizeof(hop_limit
));
2097 rv
= sendmsg(icmp_listener
.io_state
->fd
, &msg_header
, 0);
2099 uint8_t *in6_addr_bytes
= ((struct sockaddr_in6
*)(msg_header
.msg_name
))->sin6_addr
.s6_addr
;
2100 SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_bytes
, in6_addr_buf
);
2101 ERROR("icmp_send: sending " PUB_S_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
" on interface " PUB_S_SRP
2102 " index %d: " PUB_S_SRP
, message
[0] == ND_ROUTER_SOLICIT
? "solicit" : "advertise",
2103 SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_bytes
, in6_addr_buf
),
2104 interface
->name
, interface
->index
, strerror(errno
));
2105 } else if ((size_t)rv
!= iov
.iov_len
) {
2106 ERROR("icmp_send: short send to interface " PUB_S_SRP
": %zd < %zd", interface
->name
, rv
, iov
.iov_len
);
2112 post_solicit_policy_evaluate(void *context
)
2114 interface_t
*interface
= context
;
2115 INFO("Done waiting for router discovery to finish on " PUB_S_SRP
, interface
->name
);
2116 interface
->router_discovery_complete
= true;
2117 interface
->router_discovery_in_progress
= false;
2118 flush_stale_routers(interface
, ioloop_timenow());
2120 // See if we need a new prefix on the interface.
2121 interface_prefix_evaluate(interface
);
2123 routing_policy_evaluate(interface
, true);
2127 dump_network_signature(char *buffer
, size_t buffer_size
, const uint8_t *signature
, long length
)
2129 char *hexp
= buffer
;
2131 size_t left
= buffer_size
;
2135 strlcpy(buffer
, "<NULL>", buffer_size
);
2138 for (i
= 0; i
< length
; i
++) {
2139 snprintf(hexp
, left
, "%02x", signature
[i
]);
2147 network_link_finalize(network_link_t
*link
)
2149 if (link
->signature
!= NULL
) {
2150 free(link
->signature
);
2155 #define network_link_create(signature, length) network_link_create_(signature, length, __FILE__, __LINE__);
2156 static network_link_t
*
2157 network_link_create_(const uint8_t *signature
, int length
, const char *file
, int line
)
2159 network_link_t
*link
= calloc(1, sizeof(*link
));
2161 if (signature
!= NULL
) {
2163 link
->signature
= malloc(length
);
2164 if (link
->signature
== NULL
) {
2165 INFO("network_link_create: no memory for signature.");
2169 memcpy(link
->signature
, signature
, length
);
2170 link
->signature_length
= length
;
2178 static CFDictionaryRef
2179 network_link_dictionary_copy(network_link_t
*link
)
2181 CFDictionaryRef dictionary
= NULL
;
2183 err
= CFPropertyListCreateFormatted(kCFAllocatorDefault
, &dictionary
,
2190 link
->signature
, (int)link
->signature_length
,
2191 link
->prefix_number
);
2194 ERROR("CFPropertyListCreateFormatted failed: %d", err
);
2199 typedef struct network_link_parse_state network_link_parse_state_t
;
2200 struct network_link_parse_state
{
2201 network_link_t
*NONNULL link
;
2205 bool prefix_number
: 1;
2209 network_link_parse(const void *key
, const void *value
, void *context
)
2211 network_link_parse_state_t
*parse_state
= context
;
2214 if (parse_state
->fail
) {
2217 if (CFGetTypeID(key
) != CFStringGetTypeID()) {
2218 ERROR("network_link_parse: dictionary key not a string.");
2219 parse_state
->fail
= true;
2223 if (CFStringCompare(key
, CFSTR("last-seen"), 0) == kCFCompareEqualTo
) {
2224 // We store the last-seen time as a uint64 encoded as a string, because there is no uint64 CFNumber type.
2225 // We store the prefix-number time as a CFNumber because it's a uint16_t.
2226 if (CFGetTypeID(value
) != CFNumberGetTypeID() ||
2227 !CFNumberGetValue(value
, kCFNumberSInt64Type
, &last_seen
))
2229 ERROR("network_link_parse: last-seen is not a valid CFNumber");
2230 parse_state
->fail
= true;
2232 // For some reason CFNumber doesn't support uint64_t, but we are assuming that since we are copying this
2233 // unchanged, there will be no error introduced by this case.
2234 // CFProperyListCreateFormatted supports uint64_t, probably by doing the same thing.
2235 parse_state
->link
->last_seen
= (uint64_t)last_seen
;
2236 parse_state
->last_seen
= true;
2238 } else if (CFStringCompare(key
, CFSTR("signature"), 0) == kCFCompareEqualTo
) {
2239 const uint8_t *data_buffer
;
2242 // We store the signature as CFData.
2243 if (CFGetTypeID(value
) != CFDataGetTypeID()) {
2244 ERROR("network_link_parse: Unable to get CFData for signature because it's not CFData.");
2245 parse_state
->fail
= true;
2247 data_buffer
= CFDataGetBytePtr(value
);
2248 data_length
= CFDataGetLength(value
);
2249 if (data_length
< 1) {
2250 parse_state
->link
->signature_length
= 0;
2251 parse_state
->link
->signature
= NULL
;
2252 parse_state
->signature
= true;
2254 parse_state
->link
->signature_length
= data_length
;
2255 parse_state
->link
->signature
= malloc(data_length
);
2256 if (parse_state
->link
->signature
== NULL
) {
2257 ERROR("network_link_parse: No memory for signature.");
2258 parse_state
->fail
= true;
2260 memcpy(parse_state
->link
->signature
, data_buffer
, data_length
);
2261 parse_state
->signature
= true;
2265 } else if (CFStringCompare(key
, CFSTR("prefix-number"), 0) == kCFCompareEqualTo
) {
2266 // We store the prefix-number time as a CFNumber because it's a uint16_t.
2267 if (CFGetTypeID(value
) != CFNumberGetTypeID() ||
2268 !CFNumberGetValue(value
, kCFNumberSInt32Type
, &parse_state
->link
->prefix_number
))
2270 ERROR("network_link_parse: prefix-number is not a valid CFNumber");
2271 parse_state
->fail
= true;
2272 } else if (parse_state
->link
->prefix_number
< 0 || parse_state
->link
->prefix_number
> UINT16_MAX
) {
2273 ERROR("network_link_parse: Invalid prefix-number: %" PRIu32
, parse_state
->link
->prefix_number
);
2274 parse_state
->fail
= true;
2276 parse_state
->prefix_number
= true;
2279 char key_buffer
[64];
2280 if (!CFStringGetCString(key
, key_buffer
, sizeof(key_buffer
), kCFStringEncodingUTF8
)) {
2281 INFO("Unexpected network link element dictionary key, but can't decode key");
2283 INFO("Unexpected network link element dictionary key " PUB_S_SRP
, key_buffer
);
2285 parse_state
->fail
= true;
2290 network_link_apply(const void *value
, void *context
)
2292 bool *success
= context
;
2293 CFDictionaryRef values
= value
;
2294 network_link_parse_state_t parse_state
;
2297 if (*success
== false) {
2301 memset(&parse_state
, 0, sizeof parse_state
);
2302 parse_state
.link
= network_link_create(NULL
, 0);
2303 if (parse_state
.link
== NULL
) {
2304 ERROR("network_link_apply: no memory for link");
2309 // Parse the dictionary into the structure.
2310 CFDictionaryApplyFunction(values
, network_link_parse
, &parse_state
);
2312 // Should have gotten three fields: last_seen, signature, prefix_number
2313 if (!parse_state
.last_seen
) {
2314 ERROR("network_link_apply: expecting last-seen");
2315 parse_state
.fail
= true;
2317 if (!parse_state
.signature
) {
2318 ERROR("network_link_apply: expecting signature");
2319 parse_state
.fail
= true;
2321 if (!parse_state
.prefix_number
) {
2322 ERROR("network_link_apply: expecting prefix-number");
2323 parse_state
.fail
= true;
2325 if (parse_state
.fail
) {
2327 RELEASE_HERE(parse_state
.link
, network_link_finalize
);
2331 dump_network_signature(hexbuf
, sizeof hexbuf
, parse_state
.link
->signature
, parse_state
.link
->signature_length
);
2333 // If the link signature hasn't been seen in over a week, there is no need to remember it. If no new links are
2334 // seen, an old signature could persist for much longer than a week, but this is okay--the goal here is to prevent
2335 // the link array from growing without bound, and whenver a link signature is added, the array is rewritte, at
2336 // which point the old link signatures will be erased.
2337 if (ioloop_timenow() - parse_state
.link
->last_seen
> 1000 * 3600 * 24 * 7) {
2338 INFO("network_link_apply: discarding link signature " PRI_S_SRP
2339 ", prefix number %d, which is more than a week old", hexbuf
, parse_state
.link
->prefix_number
);
2340 RELEASE_HERE(parse_state
.link
, network_link_finalize
);
2344 parse_state
.link
->next
= network_links
;
2345 network_links
= parse_state
.link
;
2346 INFO("network_link_apply: parsed link signature " PRI_S_SRP
", prefix number %d", hexbuf
,
2347 network_links
->prefix_number
);
2348 // This is a temporary fix to clean up bogus link prefixes that may exist in preferences.
2349 if (network_links
->prefix_number
== 0) {
2350 network_links
->prefix_number
= ula_serial
++;
2352 if (network_links
->prefix_number
>= ula_serial
) {
2353 ula_serial
= network_links
->prefix_number
+ 1;
2359 network_link_record(network_link_t
*link
)
2362 CFDictionaryRef link_dictionary
;
2363 if (network_link_array
== NULL
) {
2364 ERROR("network_link_record: no network_link_array, can't record new link.");
2367 link_dictionary
= network_link_dictionary_copy(link
);
2368 if (link_dictionary
== NULL
) {
2369 ERROR("network_link_record: can't convert link into dictionary");
2372 CFArrayAppendValue(network_link_array
, link_dictionary
);
2374 CFPreferencesSetValue(CFSTR("network-links"), network_link_array
,
2375 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2376 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2377 if (!CFPreferencesSynchronize(CFSTR("com.apple.srp-mdns-proxy.preferences"),
2378 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
)) {
2379 ERROR("network_link_record: CFPreferencesSynchronize: Unable to store network link array.");
2381 CFRelease(link_dictionary
);
2382 dump_network_signature(hexbuf
, sizeof hexbuf
, link
->signature
, link
->signature_length
);
2383 INFO("network_link_record: recording link signature " PRI_S_SRP
", prefix number %d", hexbuf
, link
->prefix_number
);
2389 char ula_prefix_buffer
[INET6_ADDRSTRLEN
];
2390 struct in6_addr old_ula_prefix
;
2391 bool prefix_changed
;
2393 // Already have a prefix?
2394 if (ula_prefix
.s6_addr
[0] == 0xfd) {
2395 old_ula_prefix
= ula_prefix
;
2396 prefix_changed
= true;
2398 prefix_changed
= false;
2401 memset(&ula_prefix
, 0, sizeof(ula_prefix
));
2402 ula_prefix
.s6_addr
[0] = 0xfd;
2403 arc4random_buf(&ula_prefix
.s6_addr
[1], 5); // 40 bits of randomness
2405 inet_ntop(AF_INET6
, &ula_prefix
, ula_prefix_buffer
, sizeof ula_prefix_buffer
);
2406 CFStringRef ula_string
= CFStringCreateWithCString(NULL
, ula_prefix_buffer
, kCFStringEncodingUTF8
);
2407 if (ula_string
== NULL
) {
2408 ERROR("ula_generate: unable to create a ULA prefix string to store in preferences.");
2410 CFPreferencesSetValue(CFSTR("ula-prefix"), ula_string
,
2411 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2412 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2413 if (!CFPreferencesSynchronize(CFSTR("com.apple.srp-mdns-proxy.preferences"),
2414 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
)) {
2415 ERROR("CFPreferencesSynchronize: Unable to store ULA prefix.");
2417 CFRelease(ula_string
);
2419 if (prefix_changed
) {
2420 SEGMENTED_IPv6_ADDR_GEN_SRP(old_ula_prefix
.s6_addr
, old_prefix_buf
);
2421 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix
.s6_addr
, new_prefix_buf
);
2422 INFO("ula-generate: prefix changed from " PRI_SEGMENTED_IPv6_ADDR_SRP
" to " PRI_SEGMENTED_IPv6_ADDR_SRP
,
2423 SEGMENTED_IPv6_ADDR_PARAM_SRP(old_ula_prefix
.s6_addr
, old_prefix_buf
),
2424 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix
.s6_addr
, new_prefix_buf
));
2426 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix
.s6_addr
, new_prefix_buf
);
2427 INFO("ula-generate: generated ULA prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
2428 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix
.s6_addr
, new_prefix_buf
));
2431 // Set up the thread prefix.
2432 my_thread_prefix
= ula_prefix
;
2433 have_thread_prefix
= true;
2439 char ula_prefix_buffer
[INET6_ADDRSTRLEN
];
2440 bool have_stored_ula_prefix
= false;
2442 // Set up the ULA in case we need it.
2443 CFPropertyListRef plist
= CFPreferencesCopyValue(CFSTR("ula-prefix"),
2444 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2445 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2446 if (plist
!= NULL
) {
2447 if (CFGetTypeID(plist
) == CFStringGetTypeID()) {
2448 if (CFStringGetCString((CFStringRef
)plist
, ula_prefix_buffer
, sizeof(ula_prefix_buffer
),
2449 kCFStringEncodingUTF8
)) {
2450 if (inet_pton(AF_INET6
, ula_prefix_buffer
, &ula_prefix
)) {
2451 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix
.s6_addr
, ula_prefix_buf
);
2452 INFO("ula_setup: re-using stored prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
2453 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix
.s6_addr
, ula_prefix_buf
));
2454 have_stored_ula_prefix
= true;
2460 // Get the list of known network links (identified by network signature)
2461 plist
= CFPreferencesCopyValue(CFSTR("network-links"),
2462 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2463 kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
);
2465 if (plist
!= NULL
) {
2466 if (CFGetTypeID(plist
) == CFArrayGetTypeID()) {
2467 bool success
= true;
2468 CFArrayApplyFunction(plist
, CFRangeMake(0,CFArrayGetCount(plist
)), network_link_apply
, &success
);
2470 network_link_array
= CFArrayCreateMutableCopy(NULL
, 0, plist
);
2471 if (network_link_array
== NULL
) {
2472 ERROR("ula_setup: no memory for network link array!");
2480 // If we didn't get any links, make an empty array.
2481 if (network_link_array
== NULL
) {
2482 network_link_array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2483 if (network_link_array
== NULL
) {
2484 ERROR("ula_setup: unable to make network_link_array.");
2486 INFO("ula_setup: created empty network_link_array.");
2490 // If we didn't already successfully fetch a stored prefix, try to store one.
2491 if (!have_stored_ula_prefix
) {
2494 // Set up the thread prefix.
2495 my_thread_prefix
= ula_prefix
;
2496 have_thread_prefix
= true;
2501 get_network_signature(interface_t
*interface
)
2503 nwi_state_t network_state
;
2504 nwi_ifstate_t interface_state
;
2506 const uint8_t *signature
= NULL
;
2507 network_link_t
*link
= NULL
;
2510 network_state
= nwi_state_copy();
2511 if (network_state
!= NULL
) {
2512 interface_state
= nwi_state_get_ifstate(network_state
, interface
->name
);
2513 if (interface_state
!= NULL
) {
2514 signature
= nwi_ifstate_get_signature(interface_state
, AF_INET
, &length
);
2515 if (signature
!= NULL
) {
2516 dump_network_signature(hexbuf
, sizeof(hexbuf
), signature
, length
);
2517 INFO("get_network_signature: interface " PUB_S_SRP
" has ipv4 signature " PRI_S_SRP
,
2518 interface
->name
, hexbuf
);
2520 signature
= nwi_ifstate_get_signature(interface_state
, AF_INET6
, &length
);
2521 if (signature
!= NULL
) {
2522 dump_network_signature(hexbuf
, sizeof(hexbuf
), signature
, length
);
2523 INFO("get_network_signature: interface " PUB_S_SRP
" has ipv6 signature " PRI_S_SRP
,
2524 interface
->name
, hexbuf
);
2526 INFO("get_network_signature: no signature on " PUB_S_SRP
, interface
->name
);
2530 if (signature
== NULL
) {
2533 for (link
= network_links
; link
!= NULL
; link
= link
->next
) {
2534 if (link
->signature_length
== length
&& (length
== 0 || !memcmp(link
->signature
, signature
, length
))) {
2539 link
= network_link_create(signature
, length
);
2541 nwi_state_release(network_state
);
2543 ERROR("get_network_signature: nwi_state_copy() failed on " PUB_S_SRP
, interface
->name
);
2546 // If we didn't get a network signature, we're going to treat that as a signature. The previous call to
2547 // network_link_create() can have the same effect.
2549 link
= network_link_create(NULL
, 0);
2552 if (link
!= NULL
&& link
->prefix_number
== 0) {
2553 // Assign a prefix number to the link.
2554 link
->prefix_number
= ula_serial
++;
2555 link
->last_seen
= ioloop_timenow();
2557 // Save this link in memory.
2558 link
->next
= network_links
;
2559 network_links
= link
;
2561 // Save this link signature in the preferences.
2562 network_link_record(link
);
2564 if (interface
->link
!= link
) {
2565 #if defined(USE_IPCONFIGURATION_SERVICE)
2566 if (interface
->on_link_prefix_configured
) {
2567 interface_prefix_deconfigure(interface
);
2570 interface
->link
= link
;
2575 start_icmp_listener(void)
2577 int sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
2579 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
2582 struct icmp6_filter filter
;
2586 ERROR("Unable to listen for icmp messages: " PUB_S_SRP
, strerror(errno
));
2591 // Only accept router advertisements and router solicits.
2592 ICMP6_FILTER_SETBLOCKALL(&filter
);
2593 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
2594 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT
, &filter
);
2595 rv
= setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filter
, sizeof(filter
));
2597 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP
".", strerror(errno
));
2602 // We want a source address and interface index
2603 rv
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &true_flag
, sizeof(true_flag
));
2605 ERROR("Can't set IPV6_RECVPKTINFO: " PUB_S_SRP
".", strerror(errno
));
2610 // We need to be able to reject RAs arriving from off-link.
2611 rv
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &true_flag
, sizeof(true_flag
));
2613 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP
".", strerror(errno
));
2618 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
2619 // Prevent our router advertisements from updating our routing table.
2620 rv
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &false_flag
, sizeof(false_flag
));
2622 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP
".", strerror(errno
));
2628 icmp_listener
.io_state
= ioloop_file_descriptor_create(sock
, NULL
, NULL
);
2629 if (icmp_listener
.io_state
== NULL
) {
2630 ERROR("No memory for ICMP I/O structure.");
2635 // Beacon out a router advertisement every three minutes.
2636 icmp_listener
.unsolicited_interval
= 180 * 1000;
2637 ioloop_add_reader(icmp_listener
.io_state
, icmp_callback
);
2639 // At this point we need to have a ULA prefix.
2646 interface_router_solicit_finalize(void *context
)
2648 interface_t
*interface
= context
;
2649 interface
->router_solicit_wakeup
= NULL
;
2653 router_solicit_callback(void *context
)
2655 interface_t
*interface
= context
;
2656 if (interface
->is_thread
) {
2657 INFO("discontinuing router solicitations on thread interface " PUB_S_SRP
, interface
->name
);
2660 if (interface
->num_solicits_sent
>= 3) {
2661 INFO("Done sending router solicitations on " PUB_S_SRP
".", interface
->name
);
2664 INFO("sending router solicitation on " PUB_S_SRP
, interface
->name
);
2665 router_solicit_send(interface
);
2667 interface
->num_solicits_sent
++;
2668 ioloop_add_wake_event(interface
->router_solicit_wakeup
,
2669 interface
, router_solicit_callback
, interface_router_solicit_finalize
,
2670 RTR_SOLICITATION_INTERVAL
* 1000 + srp_random16() % 1024);
2674 start_router_solicit(interface_t
*interface
)
2676 if (interface
->router_solicit_wakeup
== NULL
) {
2677 interface
->router_solicit_wakeup
= ioloop_wakeup_create();
2678 if (interface
->router_solicit_wakeup
== 0) {
2679 ERROR("No memory for router solicit wakeup on " PUB_S_SRP
".", interface
->name
);
2683 ioloop_cancel_wake_event(interface
->router_solicit_wakeup
);
2685 interface
->num_solicits_sent
= 0;
2686 ioloop_add_wake_event(interface
->router_solicit_wakeup
, interface
, router_solicit_callback
,
2687 interface_router_solicit_finalize
, 128 + srp_random16() % 896);
2691 icmp_interface_subscribe(interface_t
*interface
, bool added
)
2693 struct ipv6_mreq req
;
2696 if (icmp_listener
.io_state
== NULL
) {
2697 ERROR("Interface subscribe without ICMP listener.");
2701 memset(&req
, 0, sizeof req
);
2702 if (interface
->index
== -1) {
2703 ERROR("icmp_interface_subscribe called before interface index fetch for " PUB_S_SRP
, interface
->name
);
2707 req
.ipv6mr_multiaddr
= in6addr_linklocal_allrouters
;
2708 req
.ipv6mr_interface
= interface
->index
;
2709 rv
= setsockopt(icmp_listener
.io_state
->fd
, IPPROTO_IPV6
, added
? IPV6_JOIN_GROUP
: IPV6_LEAVE_GROUP
, &req
,
2712 ERROR("Unable to " PUB_S_SRP
" all-routers multicast group on " PUB_S_SRP
": " PUB_S_SRP
,
2713 added
? "join" : "leave", interface
->name
, strerror(errno
));
2716 INFO("icmp_interface_subscribe: " PUB_S_SRP
"subscribed on interface " PUB_S_SRP
, added
? "" : "un",
2721 static interface_t
*
2722 find_interface(const char *name
, int ifindex
)
2724 interface_t
**p_interface
, *interface
= NULL
;
2726 for (p_interface
= &interfaces
; *p_interface
; p_interface
= &(*p_interface
)->next
) {
2727 interface
= *p_interface
;
2728 if (!strcmp(name
, interface
->name
)) {
2729 if (ifindex
!= -1 && interface
->index
!= ifindex
) {
2730 INFO("interface name " PUB_S_SRP
" index changed from %d to %d", name
, interface
->index
, ifindex
);
2731 interface
->index
= ifindex
;
2737 // If it's a new interface, make a structure.
2738 // We could do a callback, but don't have a use case
2739 if (*p_interface
== NULL
) {
2740 interface
= interface_create(name
, ifindex
);
2741 *p_interface
= interface
;
2746 NW_EXPORT_PROJECT NW_RETURNS_RETAINED nw_path_evaluator_t
2747 nw_path_create_evaluator_for_listener(nw_parameters_t parameters
,
2751 interface_shutdown(interface_t
*interface
)
2753 icmp_message_t
*router
, *next
;
2754 INFO("Interface " PUB_S_SRP
" went away.", interface
->name
);
2755 if (interface
->beacon_wakeup
!= NULL
) {
2756 ioloop_cancel_wake_event(interface
->beacon_wakeup
);
2758 if (interface
->post_solicit_wakeup
!= NULL
) {
2759 ioloop_cancel_wake_event(interface
->post_solicit_wakeup
);
2761 if (interface
->router_solicit_wakeup
!= NULL
) {
2762 ioloop_cancel_wake_event(interface
->router_solicit_wakeup
);
2764 if (interface
->deconfigure_wakeup
!= NULL
) {
2765 ioloop_cancel_wake_event(interface
->deconfigure_wakeup
);
2767 if (interface
->vicarious_discovery_complete
!= NULL
) {
2768 ioloop_cancel_wake_event(interface
->vicarious_discovery_complete
);
2770 for (router
= interface
->routers
; router
; router
= next
) {
2771 next
= router
->next
;
2772 icmp_message_free(router
);
2774 interface
->routers
= NULL
;
2775 if (interface
->ip_configuration_service
!= NULL
) {
2776 CFRelease(interface
->ip_configuration_service
);
2777 interface
->ip_configuration_service
= NULL
;
2779 interface
->last_beacon
= interface
->next_beacon
= 0;
2780 interface
->deprecate_deadline
= 0;
2781 interface
->preferred_lifetime
= interface
->valid_lifetime
= 0;
2782 interface
->num_solicits_sent
= 0;
2783 interface
->inactive
= true;
2784 interface
->ineligible
= true;
2785 interface
->advertise_ipv6_prefix
= false;
2786 interface
->have_link_layer_address
= false;
2787 interface
->on_link_prefix_configured
= false;
2788 interface
->sent_first_beacon
= false;
2789 interface
->num_beacons_sent
= 0;
2790 interface
->router_discovery_complete
= false;
2791 interface
->router_discovery_in_progress
= false;
2792 interface
->vicarious_router_discovery_in_progress
= false;
2793 interface
->link
= NULL
;
2797 interface_prefix_evaluate(interface_t
*interface
)
2801 // We are assuming here that the network signature can't change without us seeing a state transition.
2802 // Cases where this assumption could be violated include unplugging a WiFi base station configured as
2803 // a bridge from one ethernet network and plugging it into a different one. We could trigger a
2804 // re-evaluation when an IPv4 address on an interface changes, and also when there had been a prefix
2805 // advertised and no longer is.
2806 get_network_signature(interface
);
2808 // This should only happen if we're really low on memory.
2809 if (interface
->link
== NULL
) {
2810 INFO("interface_prefix_evaluate: newly active interface " PUB_S_SRP
" has no link.", interface
->name
);
2813 if (interface
->link
->primary
!= NULL
&&
2814 (interface
->link
->primary
->inactive
|| interface
->link
->primary
->ineligible
))
2816 INFO("Removing primary interface " PUB_S_SRP
" from link because it's inactive or ineligible.",
2817 interface
->link
->primary
->name
);
2818 interface
->link
->primary
= NULL
;
2821 if (interface
->link
->primary
== NULL
) {
2822 // Make this interface primary for the link.
2823 interface
->link
->primary
= interface
;
2825 // Set up the interface prefix using the prefix number for the link.
2826 interface
->ipv6_prefix
= ula_prefix
;
2827 interface
->ipv6_prefix
.s6_addr
[6] = interface
->link
->prefix_number
>> 8;
2828 interface
->ipv6_prefix
.s6_addr
[7] = interface
->link
->prefix_number
& 255;
2830 dump_network_signature(hexbuf
, sizeof(hexbuf
), interface
->link
->signature
,
2831 interface
->link
->signature_length
);
2832 SEGMENTED_IPv6_ADDR_GEN_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
);
2833 INFO("Interface " PUB_S_SRP
" is now primary for network " PRI_S_SRP
" with prefix "
2834 PRI_SEGMENTED_IPv6_ADDR_SRP
, interface
->name
, hexbuf
,
2835 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface
->ipv6_prefix
.s6_addr
, ipv6_prefix_buf
));
2837 if (interface
->link
->primary
!= interface
) {
2838 INFO("interface_prefix_evaluate: not setting up " PUB_S_SRP
" because interface " PUB_S_SRP
2839 " is primary for the link.", interface
->name
, interface
->link
->primary
->name
);
2846 interface_active_state_evaluate(interface_t
*interface
, bool active_known
, bool active
)
2848 INFO("interface_active_state_evaluate: evaluating interface active status - ifname: " PUB_S_SRP
2849 ", active_known: " PUB_S_SRP
", active: " PUB_S_SRP
", inactive: " PUB_S_SRP
,
2850 interface
->name
, active_known
? "true" : "false", active
? "true" : "false",
2851 interface
->inactive
? "true" : "false");
2853 if (active_known
&& !active
) {
2854 if (!interface
->inactive
) {
2855 // If we are the primary interface for the link to which we were connected, see if there's
2856 // another interface on the link and in any case make this interface not primary for that
2858 if (interface
->link
!= NULL
&& interface
->link
->primary
== interface
) {
2860 interface
->link
->primary
= NULL
;
2861 for (scan
= interfaces
; scan
; scan
= scan
->next
) {
2862 if (scan
!= interface
&& scan
->link
== interface
->link
&& !scan
->inactive
&& !scan
->ineligible
) {
2863 // Set up the thread-local prefix
2864 interface_prefix_evaluate(scan
);
2866 // We need to reevaluate routing policy on the new primary interface now, because
2867 // there may be no new event there to trigger one.
2868 routing_policy_evaluate(scan
, true);
2875 icmp_interface_subscribe(interface
, false);
2876 interface_shutdown(interface
);
2878 // Zero IPv4 addresses.
2879 interface
->num_ipv4_addresses
= 0;
2881 INFO("interface_active_state_evaluate: interface went down - ifname: " PUB_S_SRP
, interface
->name
);
2883 } else if (active_known
) {
2884 if (interface
->inactive
) {
2885 INFO("interface_active_state_evaluate: interface " PUB_S_SRP
" showed up.", interface
->name
);
2887 if (!strcmp(interface
->name
, thread_interface_name
) || !strcmp(interface
->name
, home_interface_name
)) {
2889 // Zero IPv4 addresses.
2890 interface
->num_ipv4_addresses
= 0;
2892 icmp_interface_subscribe(interface
, true);
2893 interface
->inactive
= false;
2895 interface_prefix_evaluate(interface
);
2897 if (partition_can_provide_routing
) {
2899 router_discovery_start(interface
);
2901 // If we already have a thread prefix, trigger beaconing now.
2902 if (published_thread_prefix
!= NULL
|| adopted_thread_prefix
!= NULL
) {
2903 interface_beacon_schedule(interface
, 0);
2905 INFO("No prefix on thread network, so not scheduling beacon.");
2909 INFO("Can't provide routing, so not scheduling beacon.");
2914 INFO("interface_active_state_evaluate: skipping interface " PUB_S_SRP
2915 " because it's not home or thread.", interface
->name
);
2923 nw_interface_state_changed(nw_interface_t iface
, int sock
, const char *name
, bool ineligible
)
2925 int ifindex
= nw_interface_get_index(iface
);
2927 bool active_known
= false;
2928 interface_t
*interface
;
2929 struct ifmediareq media_request
;
2931 interface
= find_interface(name
, ifindex
);
2932 if (interface
== NULL
) {
2939 if (interface
->ineligible
) {
2940 INFO("nw_interface_state_changed: interface " PUB_S_SRP
" is eligible to be used for routing.", name
);
2942 interface
->ineligible
= false;
2944 INFO("nw_interface_state_changed: interface " PUB_S_SRP
" index %d: " PUB_S_SRP
", " PUB_S_SRP
")",
2945 name
, ifindex
, (active_known
? (active
? "active" : "inactive") : "unknown"),
2946 ineligible
? "ineligible" : "eligible");
2949 memset(&media_request
, 0, sizeof(media_request
));
2950 strlcpy(media_request
.ifm_name
, name
, sizeof(media_request
.ifm_name
));
2951 if (ioctl(sock
, SIOCGIFXMEDIA
, (caddr_t
)&media_request
) >= 0) {
2952 if (media_request
.ifm_status
& IFM_ACTIVE
) {
2954 active_known
= true;
2957 active_known
= true;
2962 active_known
= false;
2965 if (interface
->index
== -1) {
2966 interface
->index
= ifindex
;
2968 interface_active_state_evaluate(interface
, active_known
, active
);
2972 ifaddr_callback(void *__unused context
, const char *name
, const addr_t
*address
, const addr_t
*mask
,
2973 unsigned flags
, enum interface_address_change change
)
2975 char addrbuf
[INET6_ADDRSTRLEN
];
2976 const uint8_t *addrbytes
, *maskbytes
, *prefp
;
2978 interface_t
*interface
;
2979 bool is_thread_interface
= false;
2981 interface
= find_interface(name
, -1);
2982 if (interface
== NULL
) {
2983 ERROR("ifaddr_callback: find_interface returned NULL for " PUB_S_SRP
, name
);
2987 if (thread_interface_name
!= NULL
&& !strcmp(name
, thread_interface_name
)) {
2988 is_thread_interface
= true;
2991 if (address
->sa
.sa_family
== AF_INET
) {
2992 addrbytes
= (uint8_t *)&address
->sin
.sin_addr
;
2993 maskbytes
= (uint8_t *)&mask
->sin
.sin_addr
;
2994 prefp
= maskbytes
+ 3;
2996 if (change
== interface_address_added
) {
2997 // Just got an IPv4 address?
2998 if (!interface
->num_ipv4_addresses
) {
2999 interface_prefix_evaluate(interface
);
3001 interface
->num_ipv4_addresses
++;
3002 } else if (change
== interface_address_deleted
) {
3003 interface
->num_ipv4_addresses
--;
3004 // Just lost our last IPv4 address?
3005 if (!interface
->num_ipv4_addresses
) {
3006 interface_prefix_evaluate(interface
);
3009 } else if (address
->sa
.sa_family
== AF_INET6
) {
3010 addrbytes
= (uint8_t *)&address
->sin6
.sin6_addr
;
3011 maskbytes
= (uint8_t *)&mask
->sin6
.sin6_addr
;
3012 prefp
= maskbytes
+ 15;
3014 } else if (address
->sa
.sa_family
== AF_LINK
) {
3015 snprintf(addrbuf
, sizeof addrbuf
, "%02x:%02x:%02x:%02x:%02x:%02x",
3016 address
->ether_addr
.addr
[0], address
->ether_addr
.addr
[1],
3017 address
->ether_addr
.addr
[2], address
->ether_addr
.addr
[3],
3018 address
->ether_addr
.addr
[4], address
->ether_addr
.addr
[5]);
3019 prefp
= (uint8_t *)&addrbuf
[0]; maskbytes
= prefp
+ 1; // Skip prefix length calculation
3023 INFO("ifaddr_callback: Unknown address type %d", address
->sa
.sa_family
);
3027 if (change
!= interface_address_unchanged
) {
3028 if (address
->sa
.sa_family
== AF_LINK
) {
3029 if (!interface
->ineligible
) {
3030 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP
" " PUB_S_SRP
" " PRI_MAC_ADDR_SRP
" flags %x",
3031 name
, is_thread_interface
? " (thread)" : "",
3032 change
== interface_address_added
? "added" : "removed",
3033 MAC_ADDR_PARAM_SRP(address
->ether_addr
.addr
), flags
);
3036 for (; prefp
>= maskbytes
; prefp
--) {
3042 for (i
= 0; i
< 8; i
++) {
3043 if (*prefp
& (1<<i
)) {
3048 inet_ntop(address
->sa
.sa_family
, addrbytes
, addrbuf
, sizeof addrbuf
);
3049 if (!interface
->ineligible
) {
3050 if (address
->sa
.sa_family
== AF_INET
) {
3051 IPv4_ADDR_GEN_SRP(addrbytes
, addr_buf
);
3052 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP
" " PUB_S_SRP
" " PRI_IPv4_ADDR_SRP
3053 "/%d flags %x", name
, is_thread_interface
? " (thread)" : "",
3054 change
== interface_address_added
? "added" : "removed",
3055 IPv4_ADDR_PARAM_SRP(addrbytes
, addr_buf
), preflen
, flags
);
3056 } else if (address
->sa
.sa_family
== AF_INET6
) {
3057 SEGMENTED_IPv6_ADDR_GEN_SRP(addrbytes
, addr_buf
);
3058 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP
" " PUB_S_SRP
" " PRI_SEGMENTED_IPv6_ADDR_SRP
3059 "/%d flags %x", name
, is_thread_interface
? " (thread)" : "",
3060 change
== interface_address_added
? "added" : "removed",
3061 SEGMENTED_IPv6_ADDR_PARAM_SRP(addrbytes
, addr_buf
), preflen
, flags
);
3063 INFO("ifaddr_callback - invalid sa_family: %d", address
->sa
.sa_family
);
3066 // When new IP address is removed, it is possible that the existing router information, such as
3067 // PIO and RIO is no longer valid since srp-mdns-proxy is losing its IP address. In order to let it to
3068 // flush the stale router information as soon as possible, we mark all the router as stale immediately,
3069 // by setting the router received time to a value which is 601s ago (router will be stale if the router
3070 // information is received for more than 600s). And then do router discovery for 20s, so we can ensure
3071 // that all the stale router information will be updated during the discovery, or flushed away. If all
3072 // routers are flushed, then srp-mdns-proxy will advertise its own prefix and configure the new IPv6
3074 if ((address
->sa
.sa_family
== AF_INET
|| address
->sa
.sa_family
== AF_INET6
) &&
3075 change
== interface_address_deleted
) {
3076 INFO("ifaddr_callback: making all routers stale and start router discovery due to removed address");
3077 adjust_router_received_time(interface
, ioloop_timenow(),
3078 -(MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE
+ MSEC_PER_SEC
));
3079 routing_policy_evaluate(interface
, false);
3085 // Not a broadcast interface
3086 if (flags
& (IFF_LOOPBACK
| IFF_POINTOPOINT
)) {
3087 // Not the thread interface
3088 if (!is_thread_interface
) {
3094 if (address
->sa
.sa_family
== AF_INET
&& IN_LINKLOCAL(address
->sin
.sin_addr
.s_addr
)) {
3098 if (interface
->index
== -1) {
3099 interface
->index
= address
->ether_addr
.index
;
3101 interface
->is_thread
= is_thread_interface
;
3103 #if TARGET_OS_TV && !defined(RA_TESTER)
3104 if (is_thread_interface
&& address
->sa
.sa_family
== AF_INET6
) {
3105 partition_utun0_address_changed(&address
->sin6
.sin6_addr
, change
);
3109 if (address
->sa
.sa_family
== AF_INET
) {
3110 } else if (address
->sa
.sa_family
== AF_INET6
) {
3111 if (IN6_IS_ADDR_LINKLOCAL(&address
->sin6
.sin6_addr
)) {
3112 interface
->link_local
= address
->sin6
.sin6_addr
;
3114 } else if (address
->sa
.sa_family
== AF_LINK
) {
3115 if (address
->ether_addr
.len
== 6) {
3116 memcpy(interface
->link_layer
, address
->ether_addr
.addr
, 6);
3117 interface
->have_link_layer_address
= true;
3123 refresh_interface_list(void)
3125 ioloop_map_interface_addresses(NULL
, ifaddr_callback
);
3129 nw_path_event(nw_path_t path
)
3131 int sock
= socket(PF_INET6
, SOCK_DGRAM
, 0);
3132 INFO("nw_path_event");
3133 nw_path_enumerate_interfaces(path
, ^bool (nw_interface_t NONNULL iface
) {
3134 const char *name
= nw_interface_get_name(iface
);
3135 CFStringRef sc_name
= CFStringCreateWithCStringNoCopy(NULL
, name
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
3136 if (sc_name
!= NULL
) {
3137 SCNetworkInterfaceRef
_SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator
,
3138 CFStringRef bsdName
, UInt32 flags
);
3139 SCNetworkInterfaceRef sc_interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, sc_name
, 0);
3141 if (sc_interface
== NULL
) {
3142 ERROR("SCNetworkInterfaceCreateWithBSDName failed");
3143 nw_interface_state_changed(iface
, sock
, name
, true);
3146 CFStringRef sc_type
= SCNetworkInterfaceGetInterfaceType(sc_interface
);
3147 if (sc_type
== NULL
) {
3148 ERROR("Unable to get interface type on " PUB_S_SRP
, name
);
3149 CFRelease(sc_interface
);
3152 CFStringRef
_SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface
);
3153 CFStringRef io_path
= _SCNetworkInterfaceGetIOPath(sc_interface
);
3154 bool is_usb
= false;
3155 if (io_path
== NULL
) {
3156 if (strncmp(name
, "utun", 4)) {
3157 ERROR("Unable to get interface I/O path.");
3160 #ifdef DEBUG_VERBOSE
3161 char pathname
[1024];
3162 CFStringGetCString(io_path
, pathname
, sizeof(pathname
), kCFStringEncodingUTF8
);
3163 INFO("Interface " PUB_S_SRP
" I/O Path: " PRI_S_SRP
, name
, pathname
);
3165 CFRange match
= CFStringFind(io_path
, CFSTR("AppleUSBDeviceNCMData"), 0);
3166 if (match
.location
!= kCFNotFound
) {
3170 if (CFEqual(sc_type
, kSCNetworkInterfaceTypeIEEE80211
) ||
3171 (CFEqual(sc_type
, kSCNetworkInterfaceTypeEthernet
) && !is_usb
))
3173 nw_interface_state_changed(iface
, sock
, name
, false);
3175 nw_interface_state_changed(iface
, sock
, name
, true);
3177 CFRelease(sc_interface
);
3182 nw_interface_state_changed(iface
, sock
, name
, true);
3188 #if TARGET_OS_TV && !defined(RA_TESTER)
3189 // If we do not have an active interface, we can't be advertising SRP service.
3190 interface_t
*interface
;
3191 bool active
= false;
3192 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
3193 if (!interface
->ineligible
&& !interface
->inactive
) {
3197 if (active
&& !have_non_thread_interface
) {
3198 INFO("nw_path_event: we have an active interface");
3199 have_non_thread_interface
= true;
3200 partition_can_advertise_service
= true;
3201 } else if (!active
&& have_non_thread_interface
) {
3202 INFO("nw_path_event: we no longer have an active interface");
3203 have_non_thread_interface
= false;
3204 // Stop advertising the service, if we are doing so.
3205 partition_discontinue_srp_service();
3207 #endif // TARGET_OS_TV && !defined(RA_TESTER)
3209 refresh_interface_list();
3212 #if TARGET_OS_TV && !defined(RA_TESTER)
3213 #ifdef GET_TUNNEL_NAME_WITH_WPANCTL
3215 thread_interface_output(io_t
*io
, void *__unused context
)
3221 // We are assuming that wpanctl will never do partial-line writes.
3222 rv
= read(io
->fd
, inbuf
, sizeof(inbuf
) - 1);
3224 ERROR("thread_interface_output: " PUB_S_SRP
, strerror(errno
));
3226 INFO("read %" PRIs64
" bytes from wpanctl output", rv
);
3228 INFO("Done with thread interface output.");
3231 if (inbuf
[rv
- 1] == '\n') {
3233 s
= strchr(inbuf
, '>');
3236 ERROR("Bad wpanctl output: " PUB_S_SRP
, inbuf
);
3243 // We don't expect the end of string here.
3248 if (s
== t
|| t
== NULL
) {
3252 if (num_thread_interfaces
!= 0) {
3253 INFO("Already have a thread interface.");
3255 num_thread_interfaces
= 1;
3256 thread_interface_name
= strdup(s
);
3257 if (thread_interface_name
== NULL
) {
3258 ERROR("No memory to save thread interface name " PUB_S_SRP
, s
);
3261 INFO("Thread interface at " PUB_S_SRP
, thread_interface_name
);
3262 partition_got_tunnel_name();
3271 thread_interface_done(void *__unused context
, int status
, const char *error
)
3273 if (error
!= NULL
) {
3274 ERROR("thread_interface_done: " PUB_S_SRP
, error
);
3276 INFO("thread_interface_done: %d.", status
);
3278 ioloop_subproc_release(thread_interface_enumerator_process
);
3280 #endif // GET_TUNNEL_NAME_WITH_WPANCTL
3283 cti_get_tunnel_name_callback(void *__unused context
, const char *name
, cti_status_t status
)
3285 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3286 INFO("cti_get_tunnel_name_callback: disconnected");
3287 adv_xpc_disconnect();
3291 INFO("cti_get_tunnel_name_callback: " PUB_S_SRP
" %d", name
!= NULL
? name
: "<null>", status
);
3292 if (status
!= kCTIStatus_NoError
) {
3295 num_thread_interfaces
= 1;
3296 if (thread_interface_name
!= NULL
) {
3297 free(thread_interface_name
);
3299 thread_interface_name
= strdup(name
);
3300 if (thread_interface_name
== NULL
) {
3301 ERROR("No memory to save thread interface name " PUB_S_SRP
, name
);
3304 INFO("Thread interface at " PUB_S_SRP
, thread_interface_name
);
3305 partition_got_tunnel_name();
3309 cti_get_role_callback(void *__unused context
, cti_network_node_type_t role
, cti_status_t status
)
3311 bool am_thread_router
= false;
3313 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3314 INFO("cti_get_role_callback: disconnected");
3315 adv_xpc_disconnect();
3319 partition_last_role_change
= ioloop_timenow();
3321 if (status
== kCTIStatus_NoError
) {
3322 if (role
== kCTI_NetworkNodeType_Router
|| role
== kCTI_NetworkNodeType_Leader
) {
3323 am_thread_router
= true;
3326 INFO("role is: " PUB_S_SRP
" (%d)\n ", am_thread_router
? "router" : "not router", role
);
3328 ERROR("cti_get_role_callback: nonzero status %d", status
);
3331 // Our thread role doesn't actually matter, but it's useful to report it in the logs.
3335 cti_get_state_callback(void *__unused context
, cti_network_state_t state
, cti_status_t status
)
3337 bool associated
= false;
3339 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3340 INFO("cti_get_state_callback: disconnected");
3341 adv_xpc_disconnect();
3345 partition_last_state_change
= ioloop_timenow();
3347 if (status
== kCTIStatus_NoError
) {
3348 if ((state
== kCTI_NCPState_Associated
) || (state
== kCTI_NCPState_Isolated
) ||
3349 (state
== kCTI_NCPState_NetWake_Asleep
) || (state
== kCTI_NCPState_NetWake_Waking
))
3354 INFO("state is: " PUB_S_SRP
" (%d)\n ", associated
? "associated" : "not associated", state
);
3356 ERROR("cti_get_state_callback: nonzero status %d", status
);
3359 if (current_thread_state
!= state
) {
3361 current_thread_state
= state
;
3362 partition_maybe_enable_services(); // but probably not
3364 current_thread_state
= state
;
3365 partition_disable_service();
3371 cti_get_partition_id_callback(void *__unused context
, int32_t partition_id
, cti_status_t status
)
3373 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3374 INFO("cti_get_partition_id_callback: disconnected");
3375 adv_xpc_disconnect();
3379 if (status
== kCTIStatus_NoError
) {
3380 INFO("Partition ID changed to %" PRIu32
, partition_id
);
3381 thread_partition_id
[0] = (uint8_t)((partition_id
>> 24) & 255);
3382 thread_partition_id
[1] = (uint8_t)((partition_id
>> 16) & 255);
3383 thread_partition_id
[2] = (uint8_t)((partition_id
>> 8) & 255);
3384 thread_partition_id
[3] = (uint8_t)(partition_id
& 255);
3386 partition_id_changed();
3388 ERROR("cti_get_state_callback: nonzero status %d", status
);
3393 thread_service_note(thread_service_t
*service
, const char *event_description
)
3397 port
= (service
->port
[0] << 8) | service
->port
[1];
3398 SEGMENTED_IPv6_ADDR_GEN_SRP(service
->address
, service_add_buf
);
3399 INFO("SRP service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d " PUB_S_SRP
,
3400 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, service_add_buf
),
3401 port
, event_description
);
3405 thread_pref_id_note(thread_pref_id_t
*pref_id
, const char *event_description
)
3407 struct in6_addr addr
;
3409 addr
.s6_addr
[0] = 0xfd;
3410 memcpy(&addr
.s6_addr
[1], pref_id
->prefix
, 5);
3411 memset(&addr
.s6_addr
[6], 0, 10);
3412 SEGMENTED_IPv6_ADDR_GEN_SRP(addr
.s6_addr
, addr_buf
);
3413 INFO("pref:id " PRI_SEGMENTED_IPv6_ADDR_SRP
":%02x%02x%02x%02x " PUB_S_SRP
,
3414 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
.s6_addr
, addr_buf
),
3415 pref_id
->partition_id
[0], pref_id
->partition_id
[1], pref_id
->partition_id
[2], pref_id
->partition_id
[3],
3419 typedef struct state_debug_accumulator
{
3420 char change
[20]; // " +stable +user +ncp"
3427 accumulator_init(accumulator_t
*accumulator
)
3429 memset(accumulator
, 0, sizeof(*accumulator
));
3430 accumulator
->p_change
= accumulator
->change
;
3431 accumulator
->left
= sizeof(accumulator
->change
);
3435 accumulate(accumulator_t
*accumulator
, bool previous
, bool cur
, const char *name
)
3438 if (previous
!= cur
) {
3439 snprintf(accumulator
->p_change
, accumulator
->left
, "%s%s%s",
3440 accumulator
->p_change
== accumulator
->change
? "" : " ", cur
? "+" : "-", name
);
3441 len
= strlen(accumulator
->p_change
);
3442 accumulator
->p_change
+= len
;
3443 accumulator
->left
-= len
;
3444 accumulator
->changed
= true;
3449 cti_service_list_callback(void *__unused context
, cti_service_vec_t
*services
, cti_status_t status
)
3452 thread_service_t
**pservice
= &thread_services
, *service
= NULL
;
3453 thread_pref_id_t
**ppref_id
= &thread_pref_ids
, *pref_id
= NULL
;
3455 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3456 INFO("cti_get_service_list_callback: disconnected");
3457 adv_xpc_disconnect();
3461 if (status
!= kCTIStatus_NoError
) {
3462 ERROR("cti_get_service_list_callback: %d", status
);
3464 // Delete any SRP services that are not in the list provided by Thread.
3465 while (*pservice
!= NULL
) {
3466 service
= *pservice
;
3467 for (i
= 0; i
< services
->num
; i
++) {
3468 cti_service_t
*cti_service
= services
->services
[i
];
3469 // Is this a valid SRP service?
3470 if (IS_SRP_SERVICE(cti_service
)) {
3471 // Is this service still present?
3472 if (!memcmp(&service
->address
, cti_service
->server
, 16) &&
3473 !memcmp(&service
->port
, &cti_service
->server
[16], 2)) {
3478 if (i
== services
->num
) {
3479 thread_service_note(service
, "went away");
3480 *pservice
= service
->next
;
3481 RELEASE_HERE(service
, thread_service_finalize
);
3483 // We'll re-initialize these flags from the service list when we check for duplicates.
3484 service
->previous_user
= service
->user
;
3485 service
->user
= false;
3486 service
->previous_stable
= service
->stable
;
3487 service
->stable
= false;
3488 service
->previous_ncp
= service
->ncp
;
3489 service
->ncp
= false;
3490 pservice
= &service
->next
;
3493 // On exit, pservice is pointing to the end-of-list pointer.
3495 // Delete any pref_id services that are not in the list provided by Thread.
3496 while (*ppref_id
!= NULL
) {
3497 pref_id
= *ppref_id
;
3498 for (i
= 0; i
< services
->num
; i
++) {
3499 cti_service_t
*cti_service
= services
->services
[i
];
3500 // Is this an SRP service?
3501 if (IS_PREF_ID_SERVICE(cti_service
)) {
3502 // Is this service still present?
3503 if (!memcmp(&pref_id
->partition_id
, cti_service
->server
, 4) &&
3504 !memcmp(pref_id
->prefix
, &cti_service
->server
[4], 5))
3510 if (i
== services
->num
) {
3511 thread_pref_id_note(pref_id
, "went away");
3512 *ppref_id
= pref_id
->next
;
3513 RELEASE_HERE(pref_id
, thread_pref_id_finalize
);
3515 // We'll re-initialize these flags from the service list when we check for duplicates.
3516 pref_id
->previous_user
= pref_id
->user
;
3517 pref_id
->user
= false;
3518 pref_id
->previous_stable
= pref_id
->stable
;
3519 pref_id
->stable
= false;
3520 pref_id
->previous_ncp
= pref_id
->ncp
;
3521 pref_id
->ncp
= false;
3522 ppref_id
= &pref_id
->next
;
3525 // On exit, pservice is pointing to the end-of-list pointer.
3527 // Add any services that are not present.
3528 for (i
= 0; i
< services
->num
; i
++) {
3529 cti_service_t
*cti_service
= services
->services
[i
];
3530 if (IS_SRP_SERVICE(cti_service
)) {
3531 for (service
= thread_services
; service
!= NULL
; service
= service
->next
) {
3532 if (!memcmp(&service
->address
, cti_service
->server
, 16) &&
3533 !memcmp(&service
->port
, &cti_service
->server
[16], 2)) {
3537 if (service
== NULL
) {
3538 service
= thread_service_create(cti_service
->server
, &cti_service
->server
[16]);
3539 if (service
== NULL
) {
3540 ERROR("cti_service_list_callback: no memory for service.");
3542 thread_service_note(service
, "showed up");
3543 *pservice
= service
;
3544 pservice
= &service
->next
;
3547 // Also, since we're combing the list, update ncp, user and stable flags. Note that a service can
3548 // appear more than once in the thread service list.
3549 if (service
!= NULL
) {
3550 if (cti_service
->flags
& kCTIFlag_NCP
) {
3551 service
->ncp
= true;
3553 service
->user
= true;
3555 if (cti_service
->flags
& kCTIFlag_Stable
) {
3556 service
->stable
= true;
3559 } else if (IS_PREF_ID_SERVICE(cti_service
)) {
3560 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= pref_id
->next
) {
3561 if (!memcmp(&pref_id
->partition_id
, cti_service
->server
, 4) &&
3562 !memcmp(pref_id
->prefix
, &cti_service
->server
[4], 5))
3567 if (pref_id
== NULL
) {
3568 pref_id
= thread_pref_id_create(cti_service
->server
, &cti_service
->server
[4]);
3569 if (pref_id
== NULL
) {
3570 ERROR("cti_service_list_callback: no memory for pref_id.");
3572 thread_pref_id_note(pref_id
, "showed up");
3573 *ppref_id
= pref_id
;
3574 ppref_id
= &pref_id
->next
;
3577 // Also, since we're combing the list, update ncp, user and stable flags. Note that a pref_id can
3578 // appear more than once in the thread pref_id list.
3579 if (pref_id
!= NULL
) {
3580 if (!pref_id
->ncp
&& (cti_service
->flags
& kCTIFlag_NCP
)) {
3581 pref_id
->ncp
= true;
3582 } else if (!pref_id
->user
&& !(cti_service
->flags
& kCTIFlag_NCP
)) {
3583 pref_id
->user
= true;
3585 if (cti_service
->flags
& kCTIFlag_Stable
) {
3586 pref_id
->stable
= true;
3592 accumulator_t accumulator
;
3593 for (service
= thread_services
; service
!= NULL
; service
= service
->next
) {
3594 accumulator_init(&accumulator
);
3595 accumulate(&accumulator
, service
->previous_ncp
, service
->ncp
, "ncp");
3596 accumulate(&accumulator
, service
->previous_stable
, service
->ncp
, "stable");
3597 accumulate(&accumulator
, service
->previous_user
, service
->user
, "user");
3598 if (accumulator
.changed
) {
3599 thread_service_note(service
, accumulator
.change
);
3602 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= pref_id
->next
) {
3603 accumulator_init(&accumulator
);
3604 accumulate(&accumulator
, pref_id
->previous_ncp
, pref_id
->ncp
, "ncp");
3605 accumulate(&accumulator
, pref_id
->previous_stable
, pref_id
->ncp
, "stable");
3606 accumulate(&accumulator
, pref_id
->previous_user
, pref_id
->user
, "user");
3607 if (accumulator
.changed
) {
3608 thread_pref_id_note(pref_id
, accumulator
.change
);
3612 // At this point the thread prefix list contains the same information as what we just received.
3613 // Trigger a "prefix set changed" event.
3614 partition_service_set_changed();
3619 cti_prefix_list_callback(void *__unused context
, cti_prefix_vec_t
*prefixes
, cti_status_t status
)
3622 thread_prefix_t
**ppref
= &thread_prefixes
, *prefix
= NULL
;
3624 if (status
== kCTIStatus_Disconnected
|| status
== kCTIStatus_DaemonNotRunning
) {
3625 INFO("cti_get_prefix_list_callback: disconnected");
3626 adv_xpc_disconnect();
3630 if (status
!= kCTIStatus_NoError
) {
3631 ERROR("cti_get_prefix_list_callback: %d", status
);
3633 // Delete any prefixes that are not in the list provided by Thread.
3634 while (*ppref
!= NULL
) {
3636 for (i
= 0; i
< prefixes
->num
; i
++) {
3637 cti_prefix_t
*cti_prefix
= prefixes
->prefixes
[i
];
3638 // Is this prefix still present?
3639 if (!memcmp(&prefix
->prefix
, &cti_prefix
->prefix
, 8)) {
3643 if (i
== prefixes
->num
) {
3644 *ppref
= prefix
->next
;
3645 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, prefix_buf
);
3646 INFO("cti_prefix_list_callback: prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" went away",
3647 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, prefix_buf
));
3648 RELEASE_HERE(prefix
, thread_prefix_finalize
);
3650 // We'll re-initialize these flags from the prefix list when we check for duplicates.
3651 prefix
->user
= false;
3652 prefix
->stable
= false;
3653 prefix
->ncp
= false;
3654 ppref
= &prefix
->next
;
3657 // On exit, ppref is pointing to the end-of-list pointer.
3659 // Add any prefixes that are not present.
3660 for (i
= 0; i
< prefixes
->num
; i
++) {
3661 cti_prefix_t
*cti_prefix
= prefixes
->prefixes
[i
];
3662 for (prefix
= thread_prefixes
; prefix
!= NULL
; prefix
= prefix
->next
) {
3663 if (!memcmp(&prefix
->prefix
, &cti_prefix
->prefix
, 16)) {
3667 if (prefix
== NULL
) {
3668 prefix
= thread_prefix_create(&cti_prefix
->prefix
, cti_prefix
->prefix_length
);
3669 if (prefix
== NULL
) {
3670 ERROR("cti_prefix_list_callback: no memory for prefix.");
3672 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, prefix_buf
);
3673 INFO("cti_prefix_list_callback: prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" showed up",
3674 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, prefix_buf
));
3676 ppref
= &prefix
->next
;
3679 // Also, since we're combing the list, update ncp, user and stable flags. Note that a prefix can
3680 // appear more than once in the thread prefix list.
3681 if (prefix
!= NULL
) {
3682 if (cti_prefix
->flags
& kCTIFlag_NCP
) {
3685 prefix
->user
= true;
3687 if (cti_prefix
->flags
& kCTIFlag_Stable
) {
3688 prefix
->stable
= true;
3693 // At this point the thread prefix list contains the same information as what we just received.
3694 // Trigger a "prefix set changed" event.
3695 partition_prefix_set_changed();
3700 get_thread_interface_list(void)
3702 #ifdef GET_TUNNEL_NAME_WITH_WPANCTL
3703 char *args
[] = { "list" };
3704 INFO("/usr/local/bin/wpanctl list");
3705 thread_interface_enumerator_process
= ioloop_subproc("/usr/local/bin/wpanctl", args
, 1,
3706 thread_interface_done
,
3707 thread_interface_output
, NULL
);
3708 if (thread_interface_enumerator_process
== NULL
) {
3709 ERROR("Unable to enumerate thread interfaces.");
3714 #endif // TARGET_OS_TV && !RA_TESTER
3716 #ifdef TCPDUMP_LOGGER
3718 tcpdump_output(io_t
*io
, void *__unused context
)
3720 static char inbuf
[1024];
3725 if (offset
+ 1 != sizeof(inbuf
)) {
3726 rv
= read(io
->fd
, &inbuf
[offset
], sizeof(inbuf
) - 1 - offset
);
3728 ERROR("tcpdump_output: " PUB_S_SRP
, strerror(errno
));
3732 INFO("Done with thread interface output.");
3739 if (offset
+ 1 == sizeof(inbuf
)) {
3742 s
= strchr(inbuf
, '\n');
3748 INFO(PUB_S_SRP
, inbuf
);
3749 if (s
!= &inbuf
[offset
]) {
3750 memmove(inbuf
, s
, &inbuf
[offset
] - s
);
3756 tcpdump_done(void *__unused context
, int status
, const char *error
)
3758 if (error
!= NULL
) {
3759 ERROR("tcpdump_done: " PUB_S_SRP
, error
);
3761 INFO("tcpdump_done: %d.", status
);
3763 ioloop_subproc_release(tcpdump_logger_process
);
3767 start_tcpdump_logger(void)
3769 char *args
[] = { "-vv", "-s", "1500", "-n", "-e", "-i", "utun0", "-l", "udp", "port", "53" };
3770 INFO("/usr/sbin/tcpdump -vv -s 1500 -n -e -i utun0 udp port 53");
3771 tcpdump_logger_process
= ioloop_subproc("/usr/sbin/tcpdump", args
, 11, tcpdump_done
,
3772 tcpdump_output
, NULL
);
3773 if (tcpdump_logger_process
== NULL
) {
3774 ERROR("Unable to start tcpdump logger.");
3777 #endif // TCPDUMP_LOGGER
3780 thread_network_startup(void)
3782 INFO("thread_network_startup: Thread network started.");
3784 #ifdef MONTIOR_ROUTING_SOCKET
3785 start_route_listener();
3788 nw_parameters_t params
= nw_parameters_create();
3789 if (path_evaluator
!= NULL
) {
3790 nw_path_evaluator_cancel(path_evaluator
);
3791 nw_release(path_evaluator
);
3793 path_evaluator
= nw_path_create_evaluator_for_listener(params
, &error
);
3795 if (path_evaluator
== NULL
|| error
!= 0) {
3796 ERROR("thread_network_startup: Unable to create network path evaluator.");
3799 nw_path_evaluator_set_update_handler(path_evaluator
, dispatch_get_main_queue(), ^(nw_path_t path
) {
3800 nw_path_event(path
);
3802 nw_path_t initial
= nw_path_evaluator_copy_path(path_evaluator
);
3803 nw_path_event(initial
);
3804 nw_release(initial
);
3805 #endif // MONITOR_ROUTING_SOCKET
3806 #if TARGET_OS_TV && !defined(RA_TESTER)
3807 get_thread_interface_list();
3809 set_thread_forwarding();
3810 #ifdef TCPDUMP_LOGGER
3811 start_tcpdump_logger();
3815 cti_get_state(&thread_state_context
, NULL
, cti_get_state_callback
, dispatch_get_main_queue());
3816 cti_get_network_node_type(&thread_role_context
, NULL
, cti_get_role_callback
, dispatch_get_main_queue());
3817 cti_get_service_list(&thread_service_context
, NULL
, cti_service_list_callback
, dispatch_get_main_queue());
3818 cti_get_prefix_list(&thread_prefix_context
, NULL
, cti_prefix_list_callback
, dispatch_get_main_queue());
3819 cti_get_tunnel_name(NULL
, cti_get_tunnel_name_callback
, dispatch_get_main_queue());
3820 cti_get_partition_id(&thread_partition_id_context
, NULL
, cti_get_partition_id_callback
, dispatch_get_main_queue());
3825 thread_network_shutdown(void)
3827 interface_t
*interface
;
3828 network_link_t
*link
;
3830 if (thread_state_context
) {
3831 INFO("thread_network_shutdown: discontinuing state events");
3832 cti_events_discontinue(thread_state_context
);
3834 if (thread_role_context
) {
3835 INFO("thread_network_shutdown: discontinuing role events");
3836 cti_events_discontinue(thread_role_context
);
3838 if (thread_service_context
) {
3839 INFO("thread_network_shutdown: discontinuing service events");
3840 cti_events_discontinue(thread_service_context
);
3842 if (thread_prefix_context
) {
3843 INFO("thread_network_shutdown: discontinuing prefix events");
3844 cti_events_discontinue(thread_prefix_context
);
3846 if (thread_partition_id_context
) {
3847 INFO("thread_network_shutdown: discontinuing partition ID events");
3848 cti_events_discontinue(thread_partition_id_context
);
3851 if (path_evaluator
!= NULL
) {
3852 nw_path_evaluator_cancel(path_evaluator
);
3853 nw_release(path_evaluator
);
3854 path_evaluator
= NULL
;
3856 INFO("thread_network_shutdown: Thread network shutdown.");
3857 // Stop all activity on interfaces.
3858 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
3859 interface_shutdown(interface
);
3861 for (link
= network_links
; link
; link
= link
->next
) {
3862 link
->primary
= NULL
;
3866 partition_state_reset();
3872 partition_state_reset(void)
3874 thread_prefix_t
*prefix
, *next_prefix
= NULL
;
3875 thread_service_t
*service
, *next_service
= NULL
;
3876 thread_pref_id_t
*pref_id
, *next_pref_id
= NULL
;
3878 // Remove any saved state from the thread network.
3879 for (prefix
= thread_prefixes
; prefix
!= NULL
; prefix
= next_prefix
) {
3880 next_prefix
= prefix
->next
;
3881 RELEASE_HERE(prefix
, thread_prefix_finalize
);
3883 thread_prefixes
= NULL
;
3885 if (published_thread_prefix
!= NULL
) {
3886 RELEASE_HERE(published_thread_prefix
, thread_prefix_finalize
);
3887 published_thread_prefix
= NULL
;
3889 if (adopted_thread_prefix
!= NULL
) {
3890 RELEASE_HERE(adopted_thread_prefix
, thread_prefix_finalize
);
3891 adopted_thread_prefix
= NULL
;
3894 for (service
= thread_services
; service
!= NULL
; service
= next_service
) {
3895 next_service
= service
->next
;
3896 RELEASE_HERE(service
, thread_service_finalize
);
3898 thread_services
= NULL
;
3900 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= next_pref_id
) {
3901 next_pref_id
= pref_id
->next
;
3902 RELEASE_HERE(pref_id
, thread_pref_id_finalize
);
3904 thread_pref_ids
= NULL
;
3906 current_thread_state
= kCTI_NCPState_Uninitialized
;
3907 current_thread_role
= kCTI_NetworkNodeType_Unknown
;
3909 partition_last_prefix_set_change
= 0;
3910 partition_last_pref_id_set_change
= 0;
3911 partition_last_partition_id_change
= 0;
3912 partition_last_role_change
= 0;
3913 partition_last_state_change
= 0;
3914 partition_settle_start
= 0;
3915 partition_service_last_add_time
= 0;
3916 partition_id_is_known
= false;
3917 partition_have_prefix_list
= false;
3918 partition_have_pref_id_list
= false;
3919 partition_tunnel_name_is_known
= false;
3920 partition_can_advertise_service
= false;
3921 partition_can_provide_routing
= false;
3922 partition_may_offer_service
= false;
3923 partition_settle_satisfied
= true;
3925 if (partition_settle_wakeup
!= NULL
) {
3926 ioloop_cancel_wake_event(partition_settle_wakeup
);
3929 if (partition_post_partition_wakeup
!= NULL
) {
3930 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
3933 if (partition_pref_id_wait_wakeup
!= NULL
) {
3934 ioloop_cancel_wake_event(partition_pref_id_wait_wakeup
);
3937 if (partition_service_add_pending_wakeup
!= NULL
) {
3938 ioloop_cancel_wake_event(partition_service_add_pending_wakeup
);
3943 prefcmp(uint8_t *a
, uint8_t *b
, int len
)
3946 for (i
= 0; i
< len
; i
++) {
3947 if (a
[i
] < b
[i
]) return -1;
3948 if (a
[i
] > b
[i
]) return 1;
3954 partition_prefix_remove_callback(void *__unused context
, cti_status_t status
)
3956 if (status
!= kCTIStatus_NoError
) {
3957 ERROR("partition_unpublish_my_prefix: failed to unpublish my prefix: %d.", status
);
3959 INFO("partition_unpublish_my_prefix: done unpublishing my prefix.");
3964 partition_stop_advertising_pref_id_done(void *__unused context
, cti_status_t status
)
3966 INFO("partition_stop_advertising_pref_id_done: %d", status
);
3970 partition_stop_advertising_pref_id(void)
3972 // This should remove any copy of the service that this BR is advertising.
3973 uint8_t service_info
[] = { 0, 0, 0, 1 };
3976 INFO("partition_stop_advertising_pref_id: %" PRIu64
"/%02x" , THREAD_ENTERPRISE_NUMBER
, service_info
[0]);
3977 service_info
[0] = THREAD_PREF_ID_OPTION
& 255;
3978 status
= cti_remove_service(NULL
, partition_stop_advertising_pref_id_done
,
3979 dispatch_get_main_queue(),
3980 THREAD_ENTERPRISE_NUMBER
, service_info
, 1);
3981 if (status
!= kCTIStatus_NoError
) {
3982 INFO("partition_stop_advertising_pref_id: status %d", status
);
3987 partition_advertise_pref_id_done(void *__unused context
, cti_status_t status
)
3989 INFO("partition_advertise_pref_id_done: %d", status
);
3993 partition_advertise_pref_id(uint8_t *prefix
)
3995 // This should remove any copy of the service that this BR is advertising.
3996 uint8_t service_info
[] = { 0, 0, 0, 1 };
3998 memcpy(pref_id
, thread_partition_id
, 4);
3999 memcpy(&pref_id
[4], prefix
, 5);
4000 uint8_t full_prefix
[6] = {0xfd, prefix
[0], prefix
[1], prefix
[2], prefix
[3], prefix
[4]};
4002 service_info
[0] = THREAD_PREF_ID_OPTION
& 255;
4003 IPv6_PREFIX_GEN_SRP(full_prefix
, sizeof(full_prefix
), prefix_buf
);
4004 INFO("partition_advertise_pref_id: %" PRIu64
"/%02x/%02x%02x%02x%02x" PRI_IPv6_PREFIX_SRP
,
4005 THREAD_ENTERPRISE_NUMBER
, service_info
[0], pref_id
[0], pref_id
[1], pref_id
[2], pref_id
[3],
4006 IPv6_PREFIX_PARAM_SRP(prefix_buf
));
4007 int status
= cti_add_service(NULL
, partition_advertise_pref_id_done
, dispatch_get_main_queue(),
4008 THREAD_ENTERPRISE_NUMBER
, service_info
, 1, pref_id
, sizeof pref_id
);
4009 if (status
!= kCTIStatus_NoError
) {
4010 INFO("partition_advertise_pref_id: status %d", status
);
4015 partition_id_update(void)
4017 thread_prefix_t
*advertised_prefix
= get_advertised_thread_prefix();
4018 if (advertised_prefix
== NULL
) {
4019 INFO("partition_id_update: no advertised prefix, not advertising pref:id.");
4020 } else if (advertised_prefix
== adopted_thread_prefix
) {
4021 INFO("partition_id_update: not advertising pref:id for adopted prefix.");
4022 partition_stop_advertising_pref_id();
4024 partition_advertise_pref_id(((uint8_t *)&advertised_prefix
->prefix
) + 1);
4025 INFO("partition_id_update: advertised pref:id for our prefix.");
4030 partition_unpublish_prefix(thread_prefix_t
*prefix
)
4032 cti_status_t status
= cti_remove_prefix(NULL
, partition_prefix_remove_callback
, dispatch_get_main_queue(),
4033 &prefix
->prefix
, 64);
4034 if (status
!= kCTIStatus_NoError
) {
4035 ERROR("partition_unpublish_prefix: prefix remove failed: %d.", status
);
4037 partition_stop_advertising_pref_id();
4041 partition_refresh_and_re_evaluate(void)
4043 refresh_interface_list();
4044 routing_policy_evaluate_all_interfaces(true);
4047 typedef struct unadvertised_prefix_remove_state unadvertised_prefix_remove_state_t
;
4048 struct unadvertised_prefix_remove_state
{
4049 int num_unadvertised_prefixes
;
4051 void (*continuation
)(void);
4055 partition_remove_all_prefixes_done(void *context
, cti_status_t status
)
4057 unadvertised_prefix_remove_state_t
*state
= context
;
4058 state
->num_removals
++;
4059 if (state
->num_removals
== state
->num_unadvertised_prefixes
) {
4060 INFO("partition_remove_all_prefixes_done: DONE: status = %d num_removals = %d num_unadvertised = %d",
4061 status
, state
->num_removals
, state
->num_unadvertised_prefixes
);
4062 void (*continuation
)(void) = state
->continuation
;
4064 if (continuation
!= NULL
) {
4067 INFO("partition_remove_all_prefixes_done: no continuation.");
4070 INFO("partition_remove_all_prefixes_done: !DONE: status = %d num_removals = %d num_unadvertised = %d",
4071 status
, state
->num_removals
, state
->num_unadvertised_prefixes
);
4076 partition_remove_all_unwanted_prefixes_inner(unadvertised_prefix_remove_state_t
*state
, thread_prefix_t
*prefix
)
4078 // Don't unpublish the adopted or published prefix.
4079 if ((published_thread_prefix
== NULL
|| memcmp(&published_thread_prefix
->prefix
, &prefix
->prefix
, 8)) &&
4080 (adopted_thread_prefix
== NULL
|| memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)))
4082 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix
->prefix
.s6_addr
, prefix_buf
);
4083 INFO("partition_remove_all_unwanted_prefixes: Removing prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4084 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix
->prefix
.s6_addr
, prefix_buf
));
4085 cti_status_t status
= cti_remove_prefix(state
, partition_remove_all_prefixes_done
,
4086 dispatch_get_main_queue(), &prefix
->prefix
, 64);
4087 if (status
!= kCTIStatus_NoError
) {
4088 ERROR("partition_remove_all_unwanted_prefixes: prefix remove failed: %d.", status
);
4094 partition_remove_all_unwanted_prefixes(void (*continuation
)(void), thread_prefix_t
*prefix_1
, thread_prefix_t
*prefix_2
)
4096 unadvertised_prefix_remove_state_t
*state
= calloc(1, sizeof(*state
));
4097 if (state
== NULL
) {
4098 INFO("partition_remove_all_unwanted_prefixes: no memory");
4102 // It's possible for us to get into a state where a prefix is published by this BR, but doesn't
4103 // have a pref:id and isn't recognized as belonging to this BR. This should never happen in practice,
4104 // but if it does happen, the only thing that will eliminate it is a reboot. In case this happens,
4105 // we go through the list of prefixes that are marked ncp and unpublish them.
4106 thread_prefix_t
*prefix
;
4108 state
->continuation
= continuation
;
4109 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4110 if (!partition_pref_id_is_present(&prefix
->prefix
)) {
4111 // It's possible for partition_remove_all_unwanted_prefixes to get called before we have a full list of
4112 // recently-published prefixes. It is possible for either the published prefix or the adopted prefix to
4113 // not be on the list of prefixes. The caller may however have wanted to change either of those pointers;
4114 // in this case, it will pass in either or both of those pointers as prefix_1 and prefix_2; if we see those
4115 // prefixes on the list, we don't need to unpublish them twice.
4116 if (prefix_1
!= NULL
&& !memcmp(&prefix
->prefix
, &prefix_1
->prefix
, 8)) {
4119 if (prefix_2
!= NULL
&& !memcmp(&prefix
->prefix
, &prefix_2
->prefix
, 8)) {
4122 state
->num_unadvertised_prefixes
++;
4125 if (prefix_1
!= NULL
) {
4126 state
->num_unadvertised_prefixes
++;
4128 if (prefix_2
!= NULL
) {
4129 state
->num_unadvertised_prefixes
++;
4132 // Now actually remove the prefixes.
4133 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4134 if (!partition_pref_id_is_present(&prefix
->prefix
)) {
4135 partition_remove_all_unwanted_prefixes_inner(state
, prefix
);
4138 if (prefix_1
!= NULL
) {
4139 partition_remove_all_unwanted_prefixes_inner(state
, prefix_1
);
4141 if (prefix_2
!= NULL
) {
4142 partition_remove_all_unwanted_prefixes_inner(state
, prefix_2
);
4145 // If we didn't remove any prefixes, continue immediately.
4146 if (state
->num_unadvertised_prefixes
== 0) {
4147 if (state
->continuation
) {
4148 state
->continuation();
4151 } else if (!state
->continuation
) {
4153 #ifdef __clang_analyzer__ // clang_analyzer is unable to follow the reference through the cti code.
4161 partition_unpublish_adopted_prefix(bool wait
)
4163 // Unpublish the adopted prefix
4164 if (adopted_thread_prefix
!= NULL
) {
4165 partition_unpublish_prefix(adopted_thread_prefix
);
4166 INFO("partition_unpublish_adopted_prefix: started to unadopt prefix.");
4167 RELEASE_HERE(adopted_thread_prefix
, thread_prefix_finalize
);
4168 adopted_thread_prefix
= NULL
;
4171 // Something changed, so do a routing policy update unless wait==true
4173 partition_refresh_and_re_evaluate();
4178 partition_publish_prefix_finish(void)
4180 INFO("partition_publish_prefix_finish: prefix unpublishing has completed, time to update the prefix.");
4182 partition_id_update();
4183 set_thread_prefix();
4185 // Something changed, so do a routing policy update.
4186 partition_refresh_and_re_evaluate();
4190 partition_publish_my_prefix()
4192 void (*continuation
)(void) = NULL
;
4193 thread_prefix_t
*prefix_1
= NULL
;
4194 thread_prefix_t
*prefix_2
= NULL
;
4196 if (adopted_thread_prefix
!= NULL
) {
4197 prefix_1
= adopted_thread_prefix
;
4198 adopted_thread_prefix
= NULL
;
4201 // If we already have a published thread prefix, it really should be my_thread_prefix.
4202 if (published_thread_prefix
!= NULL
) {
4203 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4204 // This should always be false.
4205 if (memcmp(&published_thread_prefix
->prefix
, &my_thread_prefix
, 8)) {
4206 INFO("partition_publish_my_prefix: Published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" is not my prefix",
4207 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4208 prefix_2
= published_thread_prefix
;
4209 published_thread_prefix
= NULL
;
4210 continuation
= partition_publish_prefix_finish
;
4212 INFO("partition_publish_my_prefix: Published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" is my prefix",
4213 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4216 if (published_thread_prefix
== NULL
) {
4217 // Publish the prefix
4218 published_thread_prefix
= thread_prefix_create(&my_thread_prefix
, 64);
4219 if (published_thread_prefix
== NULL
) {
4220 ERROR("partition_publish_my_prefix: No memory for locally-advertised thread prefix");
4223 continuation
= partition_publish_prefix_finish
;
4224 SEGMENTED_IPv6_ADDR_GEN_SRP(my_thread_prefix
.s6_addr
, prefix_buf
);
4225 INFO("partition_publish_my_prefix: Publishing my prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4226 SEGMENTED_IPv6_ADDR_PARAM_SRP(my_thread_prefix
.s6_addr
, prefix_buf
));
4228 partition_remove_all_unwanted_prefixes(continuation
, prefix_1
, prefix_2
);
4230 if (prefix_1
!= NULL
) {
4231 RELEASE_HERE(prefix_1
, thread_prefix_finalize
);
4233 if (prefix_2
!= NULL
) {
4234 RELEASE_HERE(prefix_2
, thread_prefix_finalize
);
4239 partition_adopt_prefix(thread_prefix_t
*prefix
)
4241 void (*continuation
)(void) = NULL
;
4242 thread_prefix_t
*prefix_1
= NULL
;
4243 thread_prefix_t
*prefix_2
= NULL
;
4245 if (published_thread_prefix
!= NULL
) {
4246 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4247 INFO("partition_adopt_prefix: Removing published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4248 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4249 prefix_1
= published_thread_prefix
;
4250 published_thread_prefix
= NULL
;
4253 // If we already have an advertised thread prefix, it might not have changed.
4254 if (adopted_thread_prefix
!= NULL
) {
4255 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4256 if (memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)) {
4257 INFO("partition_adopt_prefix: Removing previously adopted prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4258 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4259 prefix_2
= adopted_thread_prefix
;
4260 continuation
= partition_publish_prefix_finish
;
4262 INFO("partition_adopt_prefix: Keeping previously adopted prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4263 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4266 if (adopted_thread_prefix
== NULL
) {
4268 adopted_thread_prefix
= prefix
;
4269 RETAIN_HERE(adopted_thread_prefix
);
4270 continuation
= partition_publish_prefix_finish
;
4271 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4272 INFO("partition_adopt_prefix: Adopting prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
4273 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4275 partition_remove_all_unwanted_prefixes(continuation
, prefix_1
, prefix_2
);
4277 if (prefix_1
!= NULL
) {
4278 RELEASE_HERE(prefix_1
, thread_prefix_finalize
);
4280 if (prefix_2
!= NULL
) {
4281 RELEASE_HERE(prefix_2
, thread_prefix_finalize
);
4285 // Check to see if a specific prefix is still present.
4287 partition_prefix_is_present(struct in6_addr
*address
, int length
)
4289 thread_prefix_t
*prefix
;
4290 // For now we assume that the comparison is as a /64.
4291 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4292 if (prefix
->prefix_len
== length
&& !memcmp((uint8_t *)&prefix
->prefix
, (uint8_t *)address
, 8)) {
4299 // Check to see if a valid pref:id for the specified prefix is present.
4301 partition_pref_id_is_present(struct in6_addr
*prefix_addr
)
4303 thread_pref_id_t
*pref_id
;
4304 uint8_t *prefix_bytes
= (uint8_t *)prefix_addr
;
4306 INFO("partition_pref_id_is_present: published_thread_prefix = %p; prefix = %p", published_thread_prefix
,
4309 // The published prefix's pref:id is always considered present.
4310 if (published_thread_prefix
!= NULL
&& !memcmp(prefix_addr
, &published_thread_prefix
->prefix
, 8)) {
4311 INFO("partition_pref_id_is_present: prefix is published prefix");
4315 for (pref_id
= thread_pref_ids
; pref_id
; pref_id
= pref_id
->next
) {
4316 // A pref:id is valid if the partition ID matches the current partition ID.
4317 // A pref:id matches a prefix if the 40 variable bits in the ULA /48 are the same.
4318 if (!memcmp(thread_partition_id
, pref_id
->partition_id
, 4) &&
4319 !memcmp(prefix_bytes
+ 1, pref_id
->prefix
, 5))
4321 INFO("partition_pref_id_is_present: pref:id is present");
4324 IPv6_PREFIX_GEN_SRP(pref_id
->prefix
, sizeof(pref_id
->prefix
), pref_id_prefix
);
4325 if (memcmp(thread_partition_id
, pref_id
->partition_id
, 4)) {
4326 INFO("partition_pref_id_is_present: "
4327 "pref:id for " PRI_IPv6_PREFIX_SRP
4328 ":%02x%02x%02x%02x does not match partition id %02x%02x%02x%02x",
4329 IPv6_PREFIX_PARAM_SRP(pref_id_prefix
),
4330 pref_id
->partition_id
[0], pref_id
->partition_id
[1], pref_id
->partition_id
[2],
4331 pref_id
->partition_id
[3],
4332 thread_partition_id
[0], thread_partition_id
[1], thread_partition_id
[2], thread_partition_id
[3]);
4334 INFO("partition_pref_id_is_present: "
4335 "pref:id for " PRI_IPv6_PREFIX_SRP
":%02x%02x%02x%02x does not match prefix %02x%02x%02x%02x%02x",
4336 IPv6_PREFIX_PARAM_SRP(pref_id_prefix
),
4337 pref_id
->partition_id
[0], pref_id
->partition_id
[1], pref_id
->partition_id
[2],
4338 pref_id
->partition_id
[3],
4339 prefix_bytes
[1], prefix_bytes
[2], prefix_bytes
[3], prefix_bytes
[4], prefix_bytes
[5]);
4346 // Find the lowest valid prefix present. The return value may be the published prefix.
4347 static thread_prefix_t
*
4348 partition_find_lowest_valid_prefix(void)
4350 thread_prefix_t
*prefix
, *lowest
= published_thread_prefix
;
4352 // Are there other prefixes published?
4353 for (prefix
= thread_prefixes
; prefix
!= NULL
; prefix
= prefix
->next
) {
4354 // The prefix we publish doesn't count.
4355 if (published_thread_prefix
!= NULL
&& !memcmp(&prefix
->prefix
, &published_thread_prefix
->prefix
, 8)) {
4358 if (partition_pref_id_is_present(&prefix
->prefix
)) {
4359 if (lowest
== NULL
|| memcmp(&prefix
->prefix
, &lowest
->prefix
, 8) < 0) {
4368 // Find the lowest valid pref:id. The return value may be the pref:id for the published prefix.
4369 static thread_pref_id_t
*
4370 partition_find_lowest_valid_pref_id(void)
4372 thread_pref_id_t
*lowest
= NULL
;
4373 thread_pref_id_t
*pref_id
;
4375 for (pref_id
= thread_pref_ids
; pref_id
!= NULL
; pref_id
= pref_id
->next
) {
4376 if (lowest
== NULL
|| memcmp(pref_id
->prefix
, lowest
->prefix
, 5) < 0) {
4383 // The prefix ID timeout has gone off. At this time we evaluate the state of the network: the fact that we
4384 // got a wakeup means that there has been no partition event and nothing has changed about the set of
4385 // prefixes published on the thread mesh since the wakeup was scheduled. We don't schedule this wakeup unless
4386 // there is more than one prefix on the thread mesh. So that means that when the wakeup is called, there
4387 // is still more than one prefix+pref:id pair active on the link--an undesirable situation. So we now
4388 // hold an election. If we lose, we drop our prefix+pref:id pair in favor of the winner. If we win,
4389 // we do nothing--we are expecting the BR(s) publishing the other prefix+pref:id pair(s) to drop them.
4391 partition_pref_id_timeout(void *__unused context
)
4393 thread_prefix_t
*prefix
= partition_find_lowest_valid_prefix();
4395 // This should never happen because we wouldn't have set the timeout.
4396 if (prefix
== NULL
) {
4397 INFO("partition_pref_id_timeout: no published prefix.");
4401 // If we won, do nothing.
4402 if (published_thread_prefix
!= NULL
&& (prefix
== published_thread_prefix
||
4403 !memcmp(&prefix
->prefix
, &published_thread_prefix
->prefix
, 8))) {
4404 INFO("partition_pref_id_timeout: published prefix is the lowest; keeping it.");
4408 // published_thread_prefix should never be null here.
4409 // If our published prefix is not the lowest prefix, then we should drop it and adopt the lowest prefix.
4410 if (published_thread_prefix
!= NULL
&& memcmp(&prefix
->prefix
, &published_thread_prefix
->prefix
, 8)) {
4411 INFO("partition_pref_id_timeout: published prefix is not lowest valid prefix. Adopting lowest valid prefix.");
4412 partition_adopt_prefix(prefix
);
4416 // We should never get here.
4417 if (adopted_thread_prefix
!= NULL
) {
4418 if (!memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)) {
4419 ERROR("partition_pref_id_timeout: no published prefix. Already adopted lowest.");
4422 // Unadopt this prefix since it's not lowest.
4423 partition_unpublish_adopted_prefix(false);
4424 // adopted_thread_prefix is now NULL
4427 // And we should never get here.
4428 ERROR("partition_pref_id_timeout: no published prefix. Adopting lowest.");
4429 partition_adopt_prefix(prefix
);
4432 // When we see a new partition, if there isn't a prefix to adopt and we aren't publishing one,
4433 // we wait n seconds to see if some other BR publishes a prefix, but also publish our own pref:id.
4434 // If no router on the partition is publishing a prefix, then after n seconds we hold an election,
4435 // choosing the pref:id with the lowest ULA. If that's this router, then we will publish our prefix,
4436 // but if not, we want to check after a bit to make sure a prefix /does/ get published. If after
4437 // another n seconds, we still don't see a valid prefix+pref:id pair, we publish our own; if this
4438 // later turns out to have been a mistake, we will hold the election again and remove the one we
4439 // published if we don't win.
4441 partition_post_election_wakeup(void *__unused context
)
4443 thread_prefix_t
*prefix
= partition_find_lowest_valid_prefix();
4445 // There is no valid prefix published. Publish ours.
4446 if (prefix
== NULL
) {
4447 INFO("partition_post_election_wakeup: no valid thread prefix present, publishing mine.");
4448 partition_publish_my_prefix();
4452 // It's perfectly valid to not have adopted the lowest prefix at this point.
4453 // However, if we have adopted a prefix, we shouldn't be here because the timeout should have been
4455 if (adopted_thread_prefix
!= NULL
&& memcmp(&adopted_thread_prefix
->prefix
, &prefix
->prefix
, 8)) {
4456 ERROR("partition_post_election_wakeup: adopted prefix is not lowest.");
4458 ERROR("partition_post_election_wakeup: adopted prefix is lowest.");
4462 // This is the initial wakeup as described under partition_post_election_wakeup. At this time
4463 // if there is a valid published pref:id pair, we adopt it; if not, then we hold an election based
4464 // on all of the on-partition pref:id pairs that we see. If we win, we publish our prefix; otherwise
4465 // give the winner time to publish its prefix.
4467 partition_post_partition_timeout(void *__unused context
)
4469 thread_prefix_t
*prefix
= partition_find_lowest_valid_prefix();
4470 thread_pref_id_t
*pref_id
;
4472 // Is there a prefix+pref:id published?
4473 // Actually at this point we should already have adopted it and the wakeup should have been canceled.
4474 if (prefix
!= NULL
) {
4475 ERROR("partition_post_partition_timeout: wakeup when there's a valid lowest prefix.");
4479 // Are there pref:id services published that list a lower ULA than ours?
4480 pref_id
= partition_find_lowest_valid_pref_id();
4482 if (pref_id
== NULL
) {
4483 INFO("There are no prefixes published, publishing my prefix.");
4484 partition_publish_my_prefix();
4488 // If not, publish ours.
4489 if (memcmp(((uint8_t *)&my_thread_prefix
) + 1, pref_id
->prefix
, 5) < 0) {
4490 INFO("partition_post_partition_timeout: my prefix id is lowest, publishing my prefix.");
4491 partition_publish_my_prefix();
4495 // If so, wait another ten seconds to see if one of them publishes a prefix
4496 // If we have adopted a prefix, set a timer after which we will drop it and start advertising if nothing has
4498 if (partition_post_partition_wakeup
!= NULL
) { // shouldn't be!
4499 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
4501 partition_post_partition_wakeup
= ioloop_wakeup_create();
4502 if (partition_post_partition_wakeup
== NULL
) {
4503 ERROR("partition_post_partition_timeout: can't allocate pref:id wait wakeup.");
4507 // Allow ten seconds for the services state to settle, after which time we should either have a pref:id backing
4508 // up a prefix, or should advertise a prefix.
4509 INFO("partition_post_partition_timeout: waiting for other BR to publish its prefixes.");
4510 ioloop_add_wake_event(partition_post_partition_wakeup
, NULL
, partition_post_election_wakeup
, NULL
, 10 * 1000);
4514 partition_proxy_listener_ready(void *__unused context
, uint16_t port
)
4516 INFO("partition_proxy_listener_ready: listening on port %d", port
);
4517 srp_service_listen_port
= port
;
4518 if (have_non_thread_interface
) {
4519 partition_can_advertise_service
= true;
4520 partition_maybe_advertise_service();
4522 partition_discontinue_srp_service();
4527 partition_start_srp_listener(void)
4529 const int max_avoid_ports
= 100;
4530 uint16_t avoid_ports
[max_avoid_ports
];
4531 int num_avoid_ports
= 0;
4532 thread_service_t
*service
;
4534 for (service
= thread_services
; service
; service
= service
->next
) {
4535 // Track the port regardless.
4536 if (num_avoid_ports
< max_avoid_ports
) {
4537 avoid_ports
[num_avoid_ports
] = (service
->port
[0] << 8) | (service
->port
[1]);
4542 INFO("partition_start_srp_listener: starting listener.");
4543 srp_listener
= srp_proxy_listen("local", avoid_ports
, num_avoid_ports
, partition_proxy_listener_ready
);
4544 if (srp_listener
== NULL
) {
4545 ERROR("partition_start_srp_listener: Unable to start SRP Proxy listener, so can't advertise it");
4551 partition_discontinue_srp_service()
4553 if (srp_listener
!= NULL
) {
4554 srp_proxy_listener_cancel(srp_listener
);
4555 srp_listener
= NULL
;
4559 memset(&srp_listener_ip_address
, 0, 16);
4560 srp_service_listen_port
= 0;
4561 partition_can_advertise_service
= false;
4563 // Stop advertising the service, if we are doing so.
4564 partition_stop_advertising_service();
4567 // An address on utun0 has changed. Evaluate what to do with our listener service.
4568 // This gets called from ifaddr_callback(). If we don't yet have a thread service configured,
4569 // it should be called for unchanged addresses as well as changed.
4571 partition_utun0_address_changed(const struct in6_addr
*addr
, enum interface_address_change change
)
4573 thread_prefix_t
*advertised_prefix
= NULL
;
4575 // Figure out what our current prefix is.
4576 if (published_thread_prefix
!= NULL
) {
4577 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4578 INFO("partition_utun0_address_changed: advertised prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
" is my prefix.",
4579 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4580 advertised_prefix
= published_thread_prefix
;
4581 } else if (adopted_thread_prefix
!= NULL
) {
4582 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
4583 INFO("partition_utun0_address_changed: advertised prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
4584 " is another router's prefix.",
4585 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
4586 advertised_prefix
= adopted_thread_prefix
;
4589 SEGMENTED_IPv6_ADDR_GEN_SRP(addr
, addr_buf
);
4590 // Is this the address we are currently using?
4591 if (!memcmp(&srp_listener_ip_address
, addr
, 16)) {
4592 // Did it go away? If so, drop the listener.
4593 if (change
== interface_address_deleted
) {
4594 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
": listener address removed.",
4595 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4596 if (srp_listener
!= NULL
) {
4597 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4598 ": canceling listener on removed address.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4599 partition_discontinue_srp_service();
4602 // This should never happen.
4603 if (change
== interface_address_added
) {
4604 ERROR("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4605 ": address we're listening on was added.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4608 // Is it on the prefix we're currently publishing?
4609 if (advertised_prefix
!= NULL
&& !memcmp(&advertised_prefix
->prefix
, addr
, 8)) {
4610 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4611 ": listener address is on the advertised prefix--no action needed.",
4612 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4614 // In this case hopefully we'll get a new IP address we _can_ listen on in a subsequent call.
4615 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4616 ": listener address is not on the advertised prefix--no action taken.",
4617 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4621 // In no case can we do anything further.
4625 // If we have a prefix, see if we need to do anything.
4626 if (advertised_prefix
!= NULL
) {
4627 // If this is not the address we are currently using, and it showed up, is it on the prefix we
4629 if (!memcmp(&advertised_prefix
->prefix
, addr
, 8)) {
4630 // If we are not listening on an address, or we are listening on an address that isn't on the
4631 // prefix we are advertising, we need to stop, if needed, and start up a new listener.
4632 if (srp_listener_ip_address
.s6_addr
[0] == 0 ||
4633 memcmp(&advertised_prefix
->prefix
, &srp_listener_ip_address
, 8))
4635 // See if we already have a listener; if so, stop it.
4636 if (srp_listener_ip_address
.s6_addr
[0] != 0) {
4637 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
": stopping old listener.",
4638 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4639 srp_proxy_listener_cancel(srp_listener
);
4640 srp_listener
= NULL
;
4642 if (srp_listener
== NULL
) {
4643 if (!have_non_thread_interface
) {
4644 INFO("partition_utun0_address_changed: not starting a listener because we have no infrastructure");
4646 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
": starting a new listener.",
4647 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4648 memcpy(&srp_listener_ip_address
, addr
, 16);
4649 srp_service_listen_port
= 0;
4650 partition_start_srp_listener();
4655 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4656 ": this address not on advertised prefix, so no action to take.",
4657 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4660 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4661 ": no advertised prefix, so no action to take.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
, addr_buf
));
4665 // We call this function to see if we have a complete, recent set of information; if not, we wait a bit for the set
4666 // to become complete, but after 500ms we assume it won't be and proceed.
4668 partition_wait_for_prefix_settling(wakeup_callback_t callback
, uint64_t now
)
4670 // Remember when we started waiting for the partition data to settle.
4671 if (partition_settle_satisfied
) {
4672 partition_settle_start
= now
;
4673 partition_settle_satisfied
= false;
4676 if (partition_settle_wakeup
!= NULL
) {
4677 ioloop_cancel_wake_event(partition_settle_wakeup
);
4680 // If we aren't able to offer service, just wait.
4681 if (!partition_may_offer_service
) {
4682 INFO("partition_wait_for_prefix_settling: not able to offer service--deferring.");
4686 // If we've gotten updates on everything, we're good to go. The reason for comparing against
4687 // partition_settle_start is that if we've been seriously throttled for some reason, it might take
4688 // more than 500ms to get a callback, even though all the events came in between when we asked
4689 // for the initial callback and when we got it. Tunnel ID shouldn't change after startup.
4690 if (partition_last_prefix_set_change
>= partition_settle_start
&&
4691 partition_last_pref_id_set_change
>= partition_settle_start
&&
4692 partition_last_partition_id_change
>= partition_settle_start
&&
4693 partition_last_role_change
>= partition_settle_start
&&
4694 partition_last_state_change
>= partition_settle_start
&& partition_tunnel_name_is_known
)
4696 partition_settle_satisfied
= true;
4697 INFO("partition_wait_for_prefix_settling: satisfied after %llums.", now
- partition_settle_start
);
4698 return false; // means don't wait
4701 // If we've waited longer than 500ms and aren't satisfied, complain, but then proceed.
4702 if (now
- partition_settle_start
>= 500) {
4703 ERROR("partition_wait_for_prefix_settling: unsatisfied after %llums", now
- partition_settle_start
);
4704 partition_settle_satisfied
= true; // not really, but there's always next time.
4705 return false; // proceed if possible.
4708 // Otherwise, wake up 500ms after we started waiting for things to settle, and reconnoiter.
4709 if (partition_settle_wakeup
== NULL
) {
4710 partition_settle_wakeup
= ioloop_wakeup_create();
4711 if (partition_settle_wakeup
== NULL
) {
4712 ERROR("partition_wait_for_prefix_settling: Unable to postpone partition settlement wakeup: no memory.");
4713 partition_settle_satisfied
= true;
4717 ioloop_add_wake_event(partition_settle_wakeup
, NULL
, callback
, NULL
, 500 - (int)(now
- partition_settle_start
));
4722 partition_got_tunnel_name(void)
4724 partition_tunnel_name_is_known
= true;
4725 refresh_interface_list();
4728 // We have a recent prefix list and either have a recent pref:id list or one probably isn't coming.
4730 partition_prefix_list_or_pref_id_list_changed(void *__unused context
)
4732 // If we haven't had a pref:id update recently, wait a bit to see if one came with the most recent network data.
4733 if (partition_wait_for_prefix_settling(partition_prefix_list_or_pref_id_list_changed
, ioloop_timenow())) {
4734 ERROR("partition_prefix_list_or_pref_id_list_changed: waiting for prefix info to settle.");
4738 // If we aren't ready to advertise service, do nothing.
4739 if (!partition_may_offer_service
) {
4740 INFO("partition_prefix_list_or_pref_id_list_changed can't offer service yet.");
4744 // If there are no prefixes, then it doesn't matter what's on the prefix ID list: publish a prefix now.
4745 if (thread_prefixes
== NULL
) {
4746 INFO("partition_prefix_list_or_pref_id_list_changed have no prefixes, publishing my prefix");
4747 partition_publish_my_prefix();
4751 // It is a failure of the thread network software for us to get to this point without knowing the thread
4752 // partition ID. We should have received it on startup. So the case where this would happen would be if
4753 // on startup we simply didn't get it, which should never happen. What we'll do if this happens is make
4755 if (partition_id_is_known
== false) {
4756 ERROR("partition_prefix_list_or_pref_id_list_changed: partition ID never showed up!");
4759 // If we are already publishing a prefix and pref:id, we don't have to do anything to the prefix right now.
4760 if (published_thread_prefix
!= NULL
) {
4761 // We do need to trigger an interface scan though.
4762 refresh_interface_list();
4764 // Also, if there's more than one prefix present, set a timer for an hour from now, at which point we will
4765 // consider dropping our prefix.
4766 if (thread_prefixes
!= NULL
&& thread_prefixes
->next
!= NULL
) {
4767 INFO("partition_prefix_list_or_pref_id_list_changed:"
4768 "published prefix is unchanged, setting up the pref:id timer");
4769 if (partition_pref_id_wait_wakeup
!= NULL
) {
4770 ioloop_cancel_wake_event(partition_pref_id_wait_wakeup
);
4772 partition_pref_id_wait_wakeup
= ioloop_wakeup_create();
4773 if (partition_pref_id_wait_wakeup
== NULL
) {
4774 ERROR("partition_prefix_list_or_pref_id_list_changed: "
4775 "Unable to set a timer to wake up after the an hour to check the partition id.");
4779 // The thread network can be pretty chaotic right after the BR comes up, so if we see a partition during the
4780 // first 60 seconds, don't treat it as a real partition event, and do the re-election in 60 seconds rather
4782 uint64_t time_since_zero
= ioloop_timenow() - partition_last_state_change
;
4783 uint32_t pref_id_timeout_time
= 3600 * 1000;
4784 if (time_since_zero
< 60 * 1000) {
4785 pref_id_timeout_time
= 60 * 1000;
4787 ioloop_add_wake_event(partition_pref_id_wait_wakeup
, NULL
, partition_pref_id_timeout
, NULL
,
4788 pref_id_timeout_time
);
4789 INFO("added partition pref id timeout");
4791 INFO("partition_prefix_list_or_pref_id_list_changed: published prefix is unchanged");
4796 // If we have adopted a prefix and the prefix and pref:id are still present, do nothing.
4797 if (adopted_thread_prefix
!= NULL
) {
4798 if (partition_prefix_is_present(&adopted_thread_prefix
->prefix
, adopted_thread_prefix
->prefix_len
) &&
4799 partition_pref_id_is_present(&adopted_thread_prefix
->prefix
))
4801 INFO("partition_prefix_list_or_pref_id_list_changed: adopted prefix is unchanged");
4804 // If the adopted prefix is no longer present, stop using it.
4805 partition_unpublish_adopted_prefix(false);
4806 // adopted_thread_prefix is now NULL.
4809 // If there is a prefix present for which there is already a matching pref:id, adopt that prefix and pref:id now.
4810 // drop the thread_post_partition_timeout timer.
4811 thread_prefix_t
*prefix
;
4812 for (prefix
= thread_prefixes
; prefix
; prefix
= prefix
->next
) {
4813 if (partition_pref_id_is_present(&prefix
->prefix
)) {
4814 INFO("partition_prefix_list_or_pref_id_list_changed: adopting new prefix");
4815 partition_adopt_prefix(prefix
);
4816 // When we adopt a prefix, it was already on-link, and quite possibly we already have an address
4817 // configured on that prefix on utun0. Calling refresh_interface_list() will trigger the listener
4818 // if in fact that's the case. If the address hasn't come up on utun0 yet, then when it comes up
4819 // that will trigger the listener.
4820 refresh_interface_list();
4823 if (partition_post_partition_wakeup
!= NULL
) {
4824 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
4828 // At this point there is a prefix, but no pref:id, and it's /not/ the prefix that we published. This
4829 // means that a partition has happened and the BR that published the prefix is on the other partition,
4830 // or else that the BR that published the prefix has gone offline and has been offline for at least
4832 // It's possible that either condition will heal, but in the meantime publish a prefix. The reason for
4833 // the urgency is that if we have a partition, and both routers are still online, then routing will be
4834 // screwed up until we publish a new prefix and migrate all the accessories on our partition to the
4836 INFO("partition_publish_prefix: there is a prefix, but no pref:id, so it's stale. Publishing my prefix.");
4837 partition_publish_my_prefix();
4840 // The list of published prefix has changed. Evaluate what to do with our partition state.
4841 // Mostly what we do when the prefix list changes is the same as what we do if the pref:id list
4842 // changes, but if we get an empty prefix list, it doesn't matter what's on the pref:id list,
4843 // so we act immediately.
4845 partition_prefix_set_changed(void)
4847 // Time stamp most recent prefix set update.
4848 partition_last_prefix_set_change
= ioloop_timenow();
4850 // Otherwise, we have a prefix list and a pref:id list, so we can make decisions.
4851 partition_prefix_list_or_pref_id_list_changed(NULL
);
4854 // The set of published pref:id's changed. Evaluate what to do with our pref:id
4856 partition_pref_id_set_changed(void)
4858 // Time stamp most recent prefix set update.
4859 partition_last_prefix_set_change
= ioloop_timenow();
4861 // Otherwise, we have a prefix list and a pref:id list, so we can make decisions.
4862 partition_prefix_list_or_pref_id_list_changed(NULL
);
4865 // The partition ID changed.
4867 partition_id_changed(void)
4869 partition_last_partition_id_change
= ioloop_timenow();
4871 // If we've never seen a partition ID before, this is not (necessarily) a partition.
4872 if (!partition_id_is_known
) {
4873 INFO("partition_id_changed: first time through.");
4874 partition_id_is_known
= true;
4878 // If we get a partition ID when we aren't a router, we should (I think!) ignore it.
4879 if (!partition_can_provide_routing
) {
4880 INFO("partition_id_changed: we aren't able to offer routing yet, so ignoring.");
4884 // If we are advertising a prefix, update our pref:id
4885 if (published_thread_prefix
!= NULL
) {
4886 INFO("partition_id_changed: updating advertised prefix id");
4887 partition_id_update();
4888 // In principle we didn't change anything material to the routing subsystem, so no need to re-evaluate current
4893 // Propose our prefix as a possible lowest prefix in case there's an election.
4894 partition_stop_advertising_pref_id();
4895 partition_advertise_pref_id(((uint8_t *)(&my_thread_prefix
)) + 1);
4897 // If we have adopted a prefix, set a timer after which we will drop it and start advertising if nothing has
4899 if (partition_post_partition_wakeup
!= NULL
) {
4900 ioloop_cancel_wake_event(partition_post_partition_wakeup
);
4902 partition_post_partition_wakeup
= ioloop_wakeup_create();
4903 if (partition_post_partition_wakeup
== NULL
) {
4904 ERROR("partition_id_changed: can't allocate pref:id wait wakeup.");
4908 // Allow ten seconds for the services state to settle, after which time we should either have a pref:id backing
4909 // up a prefix, or should advertise a prefix.
4910 INFO("partition_id_changed: waiting for other BRs to propose their prefixes.");
4911 ioloop_add_wake_event(partition_post_partition_wakeup
, NULL
, partition_post_partition_timeout
, NULL
, 10 * 1000);
4915 partition_remove_service_done(void *context
, cti_status_t status
)
4917 INFO("partition_remove_service_done: %d", status
);
4919 // Flush any advertisements we're currently doing, since the accessories that advertised them will
4920 // notice the service is gone and start advertising with a different service.
4922 // The conditional test is so that we don't do this twice when we are advertising both services.
4924 if (context
!= NULL
) {
4930 partition_stop_advertising_service(void)
4932 // This should remove any copy of the service that this BR is advertising.
4933 INFO("partition_stop_advertising_service: %" PRIu64
"/" PUB_S_SRP
, THREAD_ENTERPRISE_NUMBER
, "00010001");
4934 uint8_t service_info
[] = { 0, 0, 0, 1 };
4937 service_info
[0] = THREAD_SRP_SERVER_OPTION
& 255;
4938 status
= cti_remove_service((void *)(ptrdiff_t)1, partition_remove_service_done
, dispatch_get_main_queue(),
4939 THREAD_ENTERPRISE_NUMBER
, service_info
, 1);
4940 if (status
!= kCTIStatus_NoError
) {
4941 INFO("partition_stop_advertising_service: status %d", status
);
4946 partition_add_service_callback(void *__unused context
, cti_status_t status
)
4948 if (status
!= kCTIStatus_NoError
) {
4949 INFO("partition_add_service_callback: status = %d", status
);
4951 INFO("partition_add_service_callback: status = %d", status
);
4956 partition_start_advertising_service(void)
4958 uint8_t service_info
[] = {0, 0, 0, 1};
4959 uint8_t server_info
[18];
4962 memcpy(&server_info
, &srp_listener_ip_address
, 16);
4963 server_info
[16] = (srp_service_listen_port
>> 8) & 255;
4964 server_info
[17] = srp_service_listen_port
& 255;
4966 service_info
[0] = THREAD_SRP_SERVER_OPTION
& 255;
4967 INFO("partition_add_srp_service: %" PRIu64
"/%02x/" PRI_SEGMENTED_IPv6_ADDR_SRP
":%d" ,
4968 THREAD_ENTERPRISE_NUMBER
, service_info
[0],
4969 SEGMENTED_IPv6_ADDR_PARAM_SRP(srp_listener_ip_address
.s6_addr
, server_ip_buf
), srp_service_listen_port
);
4971 ret
= cti_add_service(NULL
, partition_add_service_callback
, dispatch_get_main_queue(),
4972 THREAD_ENTERPRISE_NUMBER
, service_info
, 1, server_info
, sizeof server_info
);
4973 if (ret
!= kCTIStatus_NoError
) {
4974 INFO("partition_add_srp_service: status %d", ret
);
4977 // Wait a while for the service add to be reflected in an event.
4978 partition_schedule_service_add_wakeup();
4982 partition_service_add_wakeup(void *__unused context
)
4984 partition_service_last_add_time
= 0;
4985 partition_maybe_advertise_service();
4989 partition_schedule_service_add_wakeup()
4991 if (partition_service_add_pending_wakeup
== NULL
) {
4992 partition_service_add_pending_wakeup
= ioloop_wakeup_create();
4993 if (partition_service_add_pending_wakeup
== NULL
) {
4994 ERROR("Can't schedule service add pending wakeup: no memory!");
4998 ioloop_cancel_wake_event(partition_service_add_pending_wakeup
);
5000 // Wait ten seconds.
5001 ioloop_add_wake_event(partition_service_add_pending_wakeup
, NULL
, partition_service_add_wakeup
, NULL
, 10 * 1000);
5005 partition_maybe_advertise_service(void)
5007 thread_service_t
*service
, *lowest
[2];
5008 int num_services
= 0;
5010 bool should_remove_service
= false;
5011 bool should_advertise_service
= false;
5012 int64_t last_add_time
;
5014 // If we aren't ready to advertise a service, there's nothing to do.
5015 if (!partition_can_advertise_service
) {
5016 INFO("partition_maybe_advertise_service: no service to advertise yet.");
5020 if (partition_service_blocked
) {
5021 INFO("partition_maybe_advertise_service: service advertising is disabled.");
5025 for (i
= 0; i
< 16; i
++) {
5026 if (srp_listener_ip_address
.s6_addr
[i
] != 0) {
5031 INFO("partition_maybe_advertise_service: no listener.");
5034 // The add service function requires a remove prior to the add, so if we are doing an add, we need to wait
5035 // for things to stabilize before allowing the removal of a service to trigger a re-evaluation.
5036 // Therefore, if we've done an add in the past ten seconds, wait ten seconds before trying another add.
5037 last_add_time
= ioloop_timenow() - partition_service_last_add_time
;
5038 INFO("partition_maybe_advertise_service: last_add_time = %" PRId64
, last_add_time
);
5039 if (last_add_time
< 10 * 1000) {
5040 partition_schedule_service_add_wakeup();
5046 for (service
= thread_services
; service
; service
= service
->next
) {
5047 int port
= service
->port
[0] | (service
->port
[1] << 8);
5048 SEGMENTED_IPv6_ADDR_GEN_SRP(service
->address
, srv_addr_buf
);
5050 // A service only counts if its prefix is present and its prefix id is present and matches the
5051 // current partition id.
5052 if (partition_prefix_is_present((struct in6_addr
*)service
->address
, 64)) {
5053 if (partition_pref_id_is_present((struct in6_addr
*)service
->address
)) {
5055 for (i
= 0; i
< 2; i
++) {
5056 if (lowest
[i
] == NULL
) {
5057 lowest
[i
] = service
;
5058 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d goes in open slot %d.",
5059 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
, i
);
5061 } else if (memcmp(service
->address
, lowest
[i
]->address
, 16) < 0) {
5064 if (lowest
[1] != NULL
) {
5065 lowport
= (lowest
[1]->port
[0] << 8) | lowest
[1]->port
[1];
5066 SEGMENTED_IPv6_ADDR_GEN_SRP(lowest
[1]->address
, lowest_1_buf
);
5067 INFO("Superseding " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d in slot 1",
5068 SEGMENTED_IPv6_ADDR_PARAM_SRP(lowest
[1]->address
, lowest_1_buf
), lowport
);
5071 lowport
= (lowest
[0]->port
[0] << 8)| lowest
[0]->port
[1];
5072 SEGMENTED_IPv6_ADDR_GEN_SRP(lowest
[0]->address
, lowest_0_buf
);
5073 INFO("Moving " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d from slot 0 to slot 1",
5074 SEGMENTED_IPv6_ADDR_PARAM_SRP(lowest
[0]->address
, lowest_0_buf
), lowport
);
5075 lowest
[1] = lowest
[0];
5077 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d goes in slot %d.",
5078 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
, i
);
5079 lowest
[i
] = service
;
5084 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d doesn't count because the pref:id is not present.",
5085 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
);
5088 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP
"%%%d doesn't count because the prefix is not present.",
5089 SEGMENTED_IPv6_ADDR_PARAM_SRP(service
->address
, srv_addr_buf
), port
);
5093 should_remove_service
= true;
5094 for (i
= 0; i
< 2; i
++) {
5095 if (lowest
[i
] == NULL
) {
5096 INFO("partition_maybe_advertise_service: adding service because there's an open slot.");
5097 should_remove_service
= false;
5098 should_advertise_service
= true;
5101 int sign
= memcmp(((uint8_t *)(&srp_listener_ip_address
)), lowest
[i
]->address
, 16);
5103 // We're already advertising the service and we win the election.
5104 // If the port hasn't changed, don't update the service
5105 uint16_t port
= (lowest
[i
]->port
[0] << 8) | lowest
[i
]->port
[1];
5106 if (port
!= srp_service_listen_port
) {
5107 INFO("partition_maybe_advertise_service: old service was present and prefix would win election.");
5108 should_remove_service
= false;
5109 should_advertise_service
= true;
5111 INFO("partition_maybe_advertise_service: service already present and would win election.");
5112 should_remove_service
= false;
5113 should_advertise_service
= false;
5116 } else if (sign
< 0) {
5117 INFO("partition_maybe_advertise_service: service not present but wins election.");
5118 should_remove_service
= false;
5119 should_advertise_service
= true;
5122 INFO("Service would not win election with lowest[%d]", i
);
5127 // Always remove service before adding it, but also remove it if it lost the election.
5128 if (should_remove_service
) {
5129 partition_stop_advertising_service();
5130 partition_service_last_add_time
= ioloop_timenow();
5132 if (should_advertise_service
) {
5133 partition_start_advertising_service();
5134 partition_service_last_add_time
= ioloop_timenow();
5139 partition_service_set_changed()
5141 partition_pref_id_set_changed();
5142 partition_maybe_advertise_service();
5145 static void partition_maybe_enable_services()
5147 bool am_associated
= current_thread_state
== kCTI_NCPState_Associated
;
5148 if (am_associated
) {
5149 INFO("partition_maybe_enable_services: "
5150 "Enabling service, which was disabled because of the thread role or state.");
5151 partition_may_offer_service
= true;
5152 partition_can_provide_routing
= true;
5153 refresh_interface_list();
5154 partition_prefix_list_or_pref_id_list_changed(NULL
);
5155 routing_policy_evaluate_all_interfaces(true);
5157 INFO("partition_maybe_enable_services: Not enabling service: " PUB_S_SRP
,
5158 am_associated
? "associated" : "!associated");
5162 static void partition_disable_service()
5164 bool done_something
= false;
5166 // When our node type or state is such that we should no longer be publishing a prefix, the NCP will
5167 // automatically remove the published prefix. In case this happens, we do not want to remember the
5168 // prefix as already having been published. So drop our recollection of the adopted and published
5169 // prefixes; this will get cleaned up when the network comes back if there's an inconsistency.
5170 if (adopted_thread_prefix
!= NULL
) {
5171 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
5172 INFO("partition_disable_service: unadopting prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
5173 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
5174 RELEASE_HERE(adopted_thread_prefix
, thread_prefix_finalize
);
5175 adopted_thread_prefix
= NULL
;
5176 done_something
= true;
5178 if (published_thread_prefix
!= NULL
) {
5179 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
);
5180 INFO("partition_disable_service: un-publishing prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
,
5181 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix
->prefix
.s6_addr
, prefix_buf
));
5182 RELEASE_HERE(published_thread_prefix
, thread_prefix_finalize
);
5183 published_thread_prefix
= NULL
;
5184 done_something
= true;
5187 // We want to always say something when we pass through this state.
5188 if (!done_something
) {
5189 INFO("partition_disable_service: nothing to do.");
5192 partition_may_offer_service
= false;
5193 partition_can_provide_routing
= false;
5200 // c-file-style: "bsd"
5201 // c-basic-offset: 4
5203 // indent-tabs-mode: nil