]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/route.c
mDNSResponder-1310.60.4.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / route.c
1 /* route.c
2 *
3 * Copyright (c) 2019-2020 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 *
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
20 * on both networks.
21 */
22
23 #include <sys/socket.h>
24 #include <net/if.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>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <arpa/inet.h>
38 #include <sys/sysctl.h>
39 #include <stdlib.h>
40
41 #ifdef IOLOOP_MACOS
42 #include <xpc/xpc.h>
43
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>
50
51 #include <CoreUtils/CoreUtils.h>
52 #endif // IOLOOP_MACOS
53
54 #ifndef OPEN_SOURCE
55 // For now, we need backwards compatibility with old service type, only on the server.
56 # define THREAD_SERVICE_SEND_BOTH 1
57 #endif
58
59 #include "srp.h"
60 #include "dns-msg.h"
61 #include "ioloop.h"
62 #include "route.h"
63 #if TARGET_OS_TV
64 #include "cti-services.h"
65 #endif
66 #include "srp-gw.h"
67 #include "srp-proxy.h"
68
69 typedef union {
70 uint16_t len;
71 struct rt_msghdr route;
72 struct if_msghdr interface;
73 struct if_msghdr2 if2;
74 struct ifa_msghdr address;
75 uint8_t bytes[512];
76 } route_message_t;
77
78 typedef struct icmp_listener {
79 io_t *io_state;
80 int sock;
81 uint32_t unsolicited_interval;
82 } icmp_listener_t;
83
84 typedef struct thread_prefix thread_prefix_t;
85 struct thread_prefix {
86 int ref_count;
87 thread_prefix_t *next;
88 struct in6_addr prefix;
89 int prefix_len;
90 bool user, ncp, stable;
91 bool previous_user, previous_ncp, previous_stable;
92 };
93 struct thread_prefix *thread_prefixes, *published_thread_prefix, *adopted_thread_prefix;
94
95 typedef struct thread_pref_id thread_pref_id_t;
96 struct thread_pref_id {
97 int ref_count;
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;
103 };
104 struct thread_pref_id *thread_pref_ids;
105
106 typedef struct thread_service thread_service_t;
107 struct thread_service {
108 int ref_count;
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;
114 };
115 struct thread_service *thread_services;
116
117 struct network_link {
118 network_link_t *next;
119 int ref_count;
120 uint64_t last_seen;
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.
125 };
126
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.
140 int ula_serial = 1;
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;
154
155 #ifndef RA_TESTER
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;
163 #endif
164
165 nw_path_evaluator_t path_evaluator;
166
167
168 #define CONFIGURE_STATIC_INTERFACE_ADDRESSES 1
169 #define USE_IPCONFIGURATION_SERVICE 1
170
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);
179 #ifndef RA_TESTER
180 static void routing_policy_evaluate_all_interfaces(bool assume_changed);
181 #endif
182 static void routing_policy_evaluate(interface_t *interface, bool assume_changed);
183 static void post_solicit_policy_evaluate(void *context);
184
185 #ifndef RA_TESTER
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);
213
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;
234 #endif
235
236 static void
237 interface_finalize(void *context)
238 {
239 interface_t *interface = context;
240 if (interface->name != NULL) {
241 free(interface->name);
242 }
243 if (interface->beacon_wakeup != NULL) {
244 ioloop_wakeup_release(interface->beacon_wakeup);
245 }
246 if (interface->post_solicit_wakeup != NULL) {
247 ioloop_wakeup_release(interface->post_solicit_wakeup);
248 }
249 if (interface->router_solicit_wakeup != NULL) {
250 ioloop_wakeup_release(interface->router_solicit_wakeup);
251 }
252 if (interface->deconfigure_wakeup != NULL) {
253 ioloop_wakeup_release(interface->deconfigure_wakeup);
254 }
255 free(interface);
256 }
257
258 void
259 interface_retain_(interface_t *interface, const char *file, int line)
260 {
261 (void)file; (void)line;
262 RETAIN(interface);
263 }
264
265 void
266 interface_release_(interface_t *interface, const char *file, int line)
267 {
268 (void)file; (void)line;
269 RELEASE(interface, interface_finalize);
270 }
271
272 interface_t *
273 interface_create_(const char *name, int ifindex, const char *file, int line)
274 {
275 interface_t *ret;
276
277 if (name == NULL) {
278 ERROR("interface_create: missing name");
279 return NULL;
280 }
281
282 ret = calloc(1, sizeof(*ret));
283 if (ret) {
284 RETAIN(ret);
285 ret->name = strdup(name);
286 if (ret->name == NULL) {
287 ERROR("interface_create: no memory for name");
288 RELEASE(ret, interface_finalize);
289 return NULL;
290 }
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);
295 return NULL;
296 }
297
298 ret->index = ifindex;
299 ret->inactive = true;
300 // Interfaces are ineligible for routing until explicitly identified as eligible.
301 ret->ineligible = true;
302 }
303 return ret;
304 }
305
306 #ifndef RA_TESTER
307 static void
308 thread_prefix_finalize(thread_prefix_t *prefix)
309 {
310 free(prefix);
311 }
312
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)
316 {
317 thread_prefix_t *prefix;
318
319 prefix = calloc(1, (sizeof *prefix));
320 if (prefix != NULL) {
321 memcpy(&prefix->prefix, address, 16);
322 prefix->prefix_len = prefix_length;
323 RETAIN(prefix);
324 }
325 return prefix;
326 }
327
328 static void
329 thread_service_finalize(thread_service_t *service)
330 {
331 free(service);
332 }
333
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)
337 {
338 thread_service_t *service;
339
340 service = calloc(1, sizeof(*service));
341 if (service != NULL) {
342 memcpy(&service->address, address, 16);
343 memcpy(&service->port, port, 2);
344 RETAIN(service);
345 }
346 return service;
347 }
348
349 static void
350 thread_pref_id_finalize(thread_pref_id_t *pref_id)
351 {
352 free(pref_id);
353 }
354
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)
358 {
359 thread_pref_id_t *pref_id;
360
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);
365 RETAIN(pref_id);
366 }
367 return pref_id;
368 }
369 #endif // RA_TESTER
370
371 static void
372 icmp_message_free(icmp_message_t *message)
373 {
374 if (message->options != NULL) {
375 free(message->options);
376 }
377 free(message);
378 }
379
380 static void
381 icmp_message_dump(icmp_message_t *message,
382 const struct in6_addr * const source_address, const struct in6_addr * const destination_address)
383 {
384 link_layer_address_t *lladdr;
385 prefix_information_t *prefix_info;
386 route_information_t *route_info;
387 int i;
388 char retransmission_timer_buf[11]; // Maximum size of a uint32_t printed as decimal.
389 char *retransmission_timer = "infinite";
390
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;
394 }
395
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);
414 } else {
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);
421 }
422
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));
429 break;
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));
433 break;
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);
440 break;
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);
447 break;
448 default:
449 INFO(" option type %d", option->type);
450 break;
451 }
452 }
453 }
454
455 static bool
456 icmp_message_parse_options(icmp_message_t *message, uint8_t *icmp_buf, unsigned length, unsigned *offset)
457 {
458 uint8_t option_type, option_length_8;
459 unsigned option_length;
460 unsigned scan_offset = *offset;
461 icmp_option_t *option;
462 uint32_t reserved32;
463 prefix_information_t *prefix_information;
464 route_information_t *route_information;
465 int prefix_bytes;
466
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)) {
470 return false;
471 }
472 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &option_length_8)) {
473 return false;
474 }
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);
478 return false;
479 }
480 scan_offset += option_length_8 * 8 - 2;
481 message->num_options++;
482 }
483 message->options = calloc(message->num_options, sizeof(*message->options));
484 if (message->options == NULL) {
485 ERROR("No memory for icmp options.");
486 return false;
487 }
488 option = message->options;
489 while (*offset < length) {
490 scan_offset = *offset;
491 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &option_type)) {
492 return false;
493 }
494 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &option_length_8)) {
495 return false;
496 }
497 // We already validated the length in the previous pass.
498 option->type = option_type;
499 option_length = option_length_8 * 8;
500
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;
511 continue;
512 }
513 option->option.link_layer_address.length = 6;
514 memcpy(option->option.link_layer_address.address, &icmp_buf[scan_offset], 6);
515 break;
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) {
520 return false;
521 }
522 // prefix length 8
523 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &prefix_information->length)) {
524 return false;
525 }
526 // flags 8a
527 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &prefix_information->flags)) {
528 return false;
529 }
530 // valid lifetime 32
531 if (!dns_u32_parse(icmp_buf, length, &scan_offset,
532 &prefix_information->valid_lifetime)) {
533 return false;
534 }
535 // preferred lifetime 32
536 if (!dns_u32_parse(icmp_buf, length, &scan_offset,
537 &prefix_information->preferred_lifetime)) {
538 return false;
539 }
540 // reserved2 32
541 if (!dns_u32_parse(icmp_buf, length, &scan_offset, &reserved32)) {
542 return false;
543 }
544 // prefix 128
545 memcpy(&prefix_information->prefix, &icmp_buf[scan_offset], 16);
546 break;
547 case icmp_option_route_information:
548 route_information = &option->option.route_information;
549
550 // route length 8
551 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &route_information->length)) {
552 return false;
553 }
554 switch(option_length) {
555 case 8:
556 prefix_bytes = 0;
557 break;
558 case 16:
559 prefix_bytes = 8;
560 break;
561 case 24:
562 prefix_bytes = 16;
563 break;
564 default:
565 ERROR("invalid route information option length %d for route length %d",
566 option_length, route_information->length);
567 return false;
568 }
569 // flags 8
570 if (!dns_u8_parse(icmp_buf, length, &scan_offset, &route_information->flags)) {
571 return false;
572 }
573 // route lifetime 32
574 if (!dns_u32_parse(icmp_buf, length, &scan_offset, &route_information->route_lifetime)) {
575 return false;
576 }
577 // route (64, 96 or 128)
578 if (prefix_bytes > 0) {
579 memcpy(&route_information->prefix, &icmp_buf[scan_offset], prefix_bytes);
580 }
581 memset(&((uint8_t *)&route_information->prefix)[prefix_bytes], 0, 16 - prefix_bytes);
582 break;
583 default:
584 case icmp_option_mtu:
585 case icmp_option_redirected_header:
586 // don't care
587 break;
588 }
589 *offset += option_length;
590 option++;
591 }
592 return true;
593 }
594
595 static void
596 set_router_mode(interface_t *interface, int mode)
597 {
598 struct in6_ifreq router_interface;
599 int sock, ret;
600
601 sock = socket(PF_INET6, SOCK_DGRAM, 0);
602 if (sock < 0) {
603 ERROR("socket(PF_INET6, SOCK_DGRAM, 0) failed " PUB_S_SRP ": " PUB_S_SRP, interface->name, strerror(errno));
604 return;
605 }
606
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;
610 // Fix this
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);
615 if (ret < 0) {
616 ERROR("Unable to enable router mode on " PUB_S_SRP ": " PUB_S_SRP, interface->name, strerror(errno));
617 } else {
618 INFO("enabled router mode for " PUB_S_SRP ": " PUB_S_SRP ".", interface->name,
619 (mode == IPV6_ROUTER_MODE_DISABLED
620 ? "disabled"
621 : (mode == IPV6_ROUTER_MODE_EXCLUSIVE ? "exclusive" : "hybrid")));
622 }
623 close(sock);
624 }
625
626
627 static void
628 interface_wakeup_finalize(void *context)
629 {
630 interface_t *interface = context;
631 interface->beacon_wakeup = NULL;
632 }
633
634 static void
635 interface_deconfigure_finalize(void *context)
636 {
637 interface_t *interface = context;
638 interface->deconfigure_wakeup = NULL;
639 }
640
641 static void
642 interface_prefix_deconfigure(void *context)
643 {
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);
648
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));
660 }
661 interface->deprecate_deadline = 0;
662 }
663
664 static void
665 interface_beacon(void *context)
666 {
667 interface_t *interface = context;
668 uint64_t now = ioloop_timenow();
669
670 INFO("interface_beacon:" PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP,
671 interface->deprecate_deadline > now ? " ddl>now" : "",
672 #ifdef RA_TESTER
673 "",
674 #else
675 partition_can_provide_routing ? " canpr" : " !canpr",
676 #endif
677 interface->advertise_ipv6_prefix ? " pio" : " !pio",
678 interface->sent_first_beacon ? "" : " first beacon");
679
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);
694 }
695 }
696
697 #ifndef RA_TESTER
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) {
701 #endif
702
703 // Send an RA.
704 router_advertisement_send(interface);
705 interface->sent_first_beacon = true;
706 interface->last_beacon = ioloop_timenow();;
707 #ifndef RA_TESTER
708 }
709 #endif
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);
713 } else {
714 interface_beacon_schedule(interface, icmp_listener.unsolicited_interval);
715 }
716 interface->num_beacons_sent++;
717 }
718
719 static void
720 interface_beacon_schedule(interface_t *interface, unsigned when)
721 {
722 uint64_t now = ioloop_timenow();
723 unsigned interval;
724
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) {
727 int mode;
728
729 #ifdef RA_TESTER
730 mode = (strcmp(interface->name, thread_interface_name) == 0) ? IPV6_ROUTER_MODE_EXCLUSIVE
731 : IPV6_ROUTER_MODE_HYBRID;
732 #else
733 mode = IPV6_ROUTER_MODE_HYBRID;
734 #endif
735 set_router_mode(interface, mode);
736 }
737
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;
741 }
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);
749 return;
750 }
751 } else {
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
754 // be a no-op.
755 ioloop_cancel_wake_event(interface->beacon_wakeup);
756 }
757 if (interface->next_beacon - now > UINT_MAX) {
758 interval = UINT_MAX;
759 } else {
760 interval = (unsigned)(interface->next_beacon - now);
761 }
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);
765 }
766
767 static void
768 router_discovery_start(interface_t *interface)
769 {
770 INFO("Starting router discovery on " PUB_S_SRP, interface->name);
771
772 // Immediately when an interface shows up, start doing router solicits.
773 start_router_solicit(interface);
774
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);
779 }
780 } else {
781 ioloop_cancel_wake_event(interface->post_solicit_wakeup);
782 }
783
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,
787 NULL, 20 * 1000);
788 }
789 interface->router_discovery_in_progress = true;
790 }
791
792 static void
793 flush_stale_routers(interface_t *interface, uint64_t now)
794 {
795 icmp_message_t *router, **p_router;
796
797 // Flush stale routers.
798 for (p_router = &interface->routers; *p_router != NULL; ) {
799 router = *p_router;
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);
807 } else {
808 p_router = &(*p_router)->next;
809 }
810 }
811 }
812
813 static void
814 router_discovery_stop(interface_t *interface, uint64_t now)
815 {
816 if (!interface->router_discovery_complete) {
817 INFO("router_discovery_stop: stopping router discovery on " PUB_S_SRP, interface->name);
818 }
819 if (interface->router_solicit_wakeup != NULL) {
820 ioloop_cancel_wake_event(interface->router_solicit_wakeup);
821 }
822 if (interface->post_solicit_wakeup != NULL) {
823 ioloop_cancel_wake_event(interface->post_solicit_wakeup);
824 }
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);
828 }
829 interface->router_discovery_complete = true;
830 interface->router_discovery_in_progress = false;
831 interface->vicarious_router_discovery_in_progress = false;
832 // clear out need_reconfigure_prefix when router_discovery_complete is set back to true.
833 interface->need_reconfigure_prefix = false;
834 flush_stale_routers(interface, now);
835
836 // See if we need a new prefix on the interface.
837 interface_prefix_evaluate(interface);
838 }
839
840 static void
841 adjust_router_received_time(interface_t *const interface, const uint64_t now, const int64_t time_adjusted)
842 {
843 icmp_message_t *router;
844
845 if (interface->routers == NULL) {
846 if (interface->advertise_ipv6_prefix) {
847 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, __ipv6_prefix);
848 INFO("adjust_router_received_time: No router information available for the interface - "
849 "ifname: " PUB_S_SRP ", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP,
850 interface->name, SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, __ipv6_prefix));
851 } else {
852 INFO("adjust_router_received_time: No router information available for the interface - "
853 "ifname: " PUB_S_SRP, interface->name);
854 }
855
856 goto exit;
857 }
858
859 for (router = interface->routers; router != NULL; router = router->next) {
860 SEGMENTED_IPv6_ADDR_GEN_SRP(router->source.s6_addr, __router_src_addr_buf);
861 // Only adjust the received time once.
862 if (router->received_time_already_adjusted) {
863 INFO("adjust_router_received_time: received time already adjusted - remaining time: %llu, "
864 "router src: " PRI_SEGMENTED_IPv6_ADDR_SRP, (now - router->received_time) / MSEC_PER_SEC,
865 SEGMENTED_IPv6_ADDR_PARAM_SRP(router->source.s6_addr, __router_src_addr_buf));
866 continue;
867 }
868 require_action_quiet(
869 (time_adjusted > 0 && (UINT64_MAX - now) > (uint64_t)time_adjusted) ||
870 (time_adjusted < 0 && now > ((uint64_t)-time_adjusted)), exit,
871 ERROR("adjust_router_received_time: invalid adjusted values is causing overflow - "
872 "now: %" PRIu64 ", time_adjusted: %" PRId64, now, time_adjusted));
873 router->received_time = now + time_adjusted;
874 router->received_time_already_adjusted = true; // Only adjust the icmp message received time once.
875 INFO("adjust_router_received_time: router received time is adjusted - router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
876 ", adjusted value: %" PRId64,
877 SEGMENTED_IPv6_ADDR_PARAM_SRP(router->source.s6_addr, __router_src_addr_buf), time_adjusted);
878 }
879
880 exit:
881 return;
882 }
883
884 static void
885 make_all_routers_nearly_stale(interface_t *interface, uint64_t now)
886 {
887 // Make every router go stale in 19.999 seconds. This means that if we don't get a response
888 // to our solicit in 20 seconds, then when the timeout callback is called, there will be no
889 // routers on the interface that aren't stale, which will trigger router discovery.
890 adjust_router_received_time(interface, now, 19999 - 600 * MSEC_PER_SEC);
891 }
892
893 static void
894 vicarious_discovery_callback(void *context)
895 {
896 interface_t *interface = context;
897 INFO("Vicarious router discovery finished on " PUB_S_SRP ".", interface->name);
898 interface->vicarious_router_discovery_in_progress = false;
899 // At this point, policy evaluate will show all the routes that were present before vicarious
900 // discovery as stale, so policy_evaluate will start router discovery if we didn't get any
901 // RAs containing on-link prefixes.
902 routing_policy_evaluate(interface, false);
903 }
904
905 #ifndef RA_TESTER
906 static void
907 routing_policy_evaluate_all_interfaces(bool assume_changed)
908 {
909 interface_t *interface;
910
911 for (interface = interfaces; interface; interface = interface->next) {
912 routing_policy_evaluate(interface, assume_changed);
913 }
914 }
915 #endif
916
917 static void
918 routing_policy_evaluate(interface_t *interface, bool assume_changed)
919 {
920 icmp_message_t *router;
921 bool new_prefix = false; // new prefix means that srp-mdns-proxy received a new prefix from the wire, which it
922 // did not know before.
923 bool on_link_prefix_present = false;
924 bool something_changed = assume_changed;
925 uint64_t now = ioloop_timenow();
926 bool stale_routers_exist = false;
927
928 // No action on interfaces that aren't eligible for routing or that isn't currently active.
929 if (interface->ineligible || interface->inactive) {
930 INFO("not evaluating policy on " PUB_S_SRP " because it's " PUB_S_SRP, interface->name,
931 interface->ineligible ? "ineligible" : "inactive");
932 return;
933 }
934
935 // See if we have a prefix from some other router
936 for (router = interface->routers; router; router = router->next) {
937 icmp_option_t *option = router->options;
938 int i;
939 if (now - router->received_time > MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE) {
940 stale_routers_exist = true;
941 SEGMENTED_IPv6_ADDR_GEN_SRP(router->source.s6_addr, router_src_addr_buf);
942 INFO("Router " PRI_SEGMENTED_IPv6_ADDR_SRP " is stale by %" PRIu64 " milliseconds",
943 SEGMENTED_IPv6_ADDR_PARAM_SRP(router->source.s6_addr, router_src_addr_buf),
944 now - router->received_time);
945 } else {
946 for (i = 0; i < router->num_options; i++) {
947 if (option->type == icmp_option_prefix_information) {
948 prefix_information_t *prefix = &option->option.prefix_information;
949 if ((prefix->flags & ND_OPT_PI_FLAG_ONLINK) &&
950 ((prefix->flags & ND_OPT_PI_FLAG_AUTO) || (router->flags & ND_RA_FLAG_MANAGED)) &&
951 prefix->preferred_lifetime > 0)
952 {
953 // If this is a new icmp_message received now and contains PIO.
954 if (router->new_router) {
955 new_prefix = true;
956 router->new_router = false; // clear the bit since srp-mdns-proxy already processed it.
957 }
958
959 // Right now all we need is to see if there is an on-link prefix.
960 on_link_prefix_present = true;
961 SEGMENTED_IPv6_ADDR_GEN_SRP(router->source.s6_addr, __router_src_add_buf);
962 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, __pio_prefix_buf);
963 DEBUG("routing_policy_evaluate: router has PIO - ifname: " PUB_S_SRP ", router src: " PRI_SEGMENTED_IPv6_ADDR_SRP
964 ", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP,
965 interface->name,
966 SEGMENTED_IPv6_ADDR_PARAM_SRP(router->source.s6_addr, __router_src_add_buf),
967 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, __pio_prefix_buf));
968 }
969 }
970 option++;
971 }
972 }
973 }
974
975 INFO("policy on " PUB_S_SRP ": " PUB_S_SRP "stale " /* stale_routers_exist ? */
976 PUB_S_SRP "disco " /* interface->router_discovery_complete ? */
977 PUB_S_SRP "present " /* on_link_prefix_present ? */
978 PUB_S_SRP "advert " /* interface->advertise_ipv6_prefix ? */
979 PUB_S_SRP "conf " /* interface->on_link_prefix_configured ? */
980 PUB_S_SRP "new_prefix " /* new_prefix ? */
981 "preferred = %" PRIu32 " valid = %" PRIu32 " deadline = %llu",
982 interface->name, stale_routers_exist ? "" : "!", interface->router_discovery_complete ? "" : "!",
983 on_link_prefix_present ? "" : "!", interface->advertise_ipv6_prefix ? "" : "!",
984 interface->on_link_prefix_configured ? "" : "!", new_prefix ? "" : "!",
985 interface->preferred_lifetime, interface->valid_lifetime, interface->deprecate_deadline);
986
987 // If there are stale routers, start doing router discovery again to see if we can get them to respond.
988 // Also, if we have not yet done router discovery, do it now.
989 if ((!interface->router_discovery_complete || stale_routers_exist) && !on_link_prefix_present) {
990 if (!interface->router_discovery_in_progress) {
991 // Start router discovery.
992 router_discovery_start(interface);
993 } else {
994 INFO("routing_policy_evaluate: router discovery in progress");
995 }
996 }
997 // If we are advertising a prefix and there's another on-link prefix, deprecate the one we are
998 // advertising.
999 else if (interface->advertise_ipv6_prefix && on_link_prefix_present) {
1000 // If we have been advertising a preferred prefix, deprecate it.
1001 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf);
1002 if (interface->preferred_lifetime != 0) {
1003 INFO("routing_policy_evaluate: deprecating interface prefix in 30 minutes - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP,
1004 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf));
1005 interface->preferred_lifetime = 0;
1006 interface->deprecate_deadline = now + 1800 * 1000;
1007 something_changed = true;
1008 } else {
1009 INFO("routing_policy_evaluate: prefix deprecating in progress - prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP,
1010 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf));
1011 }
1012 }
1013 // If there is no on-link prefix and we aren't advertising, or have deprecated, start advertising
1014 // again (or for the first time).
1015 else if (!on_link_prefix_present && interface->router_discovery_complete &&
1016 interface->link != NULL && interface->link->primary == interface &&
1017 (!interface->advertise_ipv6_prefix || interface->deprecate_deadline != 0 ||
1018 interface->preferred_lifetime == 0)) {
1019
1020 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf);
1021 INFO("routing_policy_evaluate: advertising prefix again - ifname: " PUB_S_SRP
1022 ", prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP, interface->name,
1023 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf));
1024
1025 // If we were deprecating, stop.
1026 ioloop_cancel_wake_event(interface->deconfigure_wakeup);
1027 interface->deprecate_deadline = 0;
1028
1029 // Start advertising immediately, 30 minutes.
1030 interface->preferred_lifetime = interface->valid_lifetime = 1800;
1031
1032 // If the on-link prefix isn't configured on the interface, do that.
1033 if (!interface->on_link_prefix_configured) {
1034 #ifndef RA_TESTER
1035 if (!interface->is_thread) {
1036 #endif
1037 interface_prefix_configure(interface->ipv6_prefix, interface);
1038 #ifndef RA_TESTER
1039 } else {
1040 INFO("Not setting up " PUB_S_SRP " because it is the thread interface", interface->name);
1041 }
1042 #endif
1043 } else {
1044 // Configuring the on-link prefix takes a while, so we want to re-evaluate after it's finished.
1045 interface->advertise_ipv6_prefix = true;
1046 something_changed = true;
1047 }
1048 }
1049 // If there is no on-link prefix present, and srp-mdns-proxy itself is advertising the prefix, and it has configured
1050 // an on-link prefix, and the interface is not thread interface, and it just got an interface address removal event,
1051 // it is possible that the IPv6 routing has been flushed due to loss of address in configd, so here we explicitly
1052 // reconfigure the IPv6 prefix and the routing.
1053 else if (interface->need_reconfigure_prefix && !on_link_prefix_present && interface->advertise_ipv6_prefix &&
1054 interface->on_link_prefix_configured && !interface->is_thread) {
1055 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf);
1056 INFO("routing_policy_evaluate: reconfigure ipv6 prefix due to possible network changes -"
1057 " prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP,
1058 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, __prefix_buf));
1059 interface_prefix_configure(interface->ipv6_prefix, interface);
1060 interface->need_reconfigure_prefix = false;
1061 }
1062
1063 // If we've been looking to see if there's an on-link prefix, and we got one from the new router advertisement,
1064 // stop looking for new one.
1065 if (new_prefix) {
1066 router_discovery_stop(interface, now);
1067 }
1068
1069 // If anything changed, do an immediate beacon; otherwise wait until the next one.
1070 // Also when something changed, set the number of transmissions back to zero so that
1071 // we send a few initial beacons quickly for reliability.
1072 if (something_changed) {
1073 INFO("change on " PUB_S_SRP ": " PUB_S_SRP "disco " PUB_S_SRP "present " PUB_S_SRP "advert " PUB_S_SRP
1074 "conf preferred = %" PRIu32 " valid = %" PRIu32 " deadline = %llu",
1075 interface->name, interface->router_discovery_complete ? "" : "!", on_link_prefix_present ? "" : "!",
1076 interface->advertise_ipv6_prefix ? "" : "!", interface->on_link_prefix_configured ? "" : "!",
1077 interface->preferred_lifetime,
1078 interface->valid_lifetime, interface->deprecate_deadline);
1079 interface->num_beacons_sent = 0;
1080 interface_beacon_schedule(interface, 0);
1081 }
1082 }
1083
1084 static void
1085 start_vicarious_router_discovery_if_appropriate(interface_t *const interface)
1086 {
1087 if (!interface->advertise_ipv6_prefix &&
1088 !interface->vicarious_router_discovery_in_progress && !interface->router_discovery_in_progress)
1089 {
1090 if (interface->vicarious_discovery_complete == NULL) {
1091 interface->vicarious_discovery_complete = ioloop_wakeup_create();
1092 } else {
1093 ioloop_cancel_wake_event(interface->vicarious_discovery_complete);
1094 }
1095 if (interface->vicarious_discovery_complete != NULL) {
1096 ioloop_add_wake_event(interface->vicarious_discovery_complete,
1097 interface, vicarious_discovery_callback, NULL, 20 * 1000);
1098 interface->vicarious_router_discovery_in_progress = true;
1099 }
1100 // In order for vicarious router discovery to be useful, we need all of the routers
1101 // that were present when the first solicit was received to be stale when we give up
1102 // on vicarious discovery. If we got any router advertisements, these will not be
1103 // stale, and that means vicarious discovery succeeded.
1104 make_all_routers_nearly_stale(interface, ioloop_timenow());
1105 INFO("start_vicarious_router_discovery_if_appropriate: Starting vicarious router discovery on " PUB_S_SRP,
1106 interface->name);
1107 }
1108 }
1109
1110 static void
1111 router_solicit(icmp_message_t *message)
1112 {
1113 interface_t *iface, *interface;
1114
1115 // Further validate the message
1116 if (message->hop_limit != 255 || message->code != 0) {
1117 ERROR("Invalid router solicitation, hop limit = %d, code = %d", message->hop_limit, message->code);
1118 }
1119 if (IN6_IS_ADDR_UNSPECIFIED(&message->source)) {
1120 icmp_option_t *option = message->options;
1121 int i;
1122 for (i = 0; i < message->num_options; i++) {
1123 if (option->type == icmp_option_source_link_layer_address) {
1124 ERROR("source link layer address in router solicitation from unspecified IP address");
1125 return;
1126 }
1127 option++;
1128 }
1129 } else {
1130 // Make sure it's not from this host
1131 for (iface = interfaces; iface; iface = iface->next) {
1132 if (iface->have_link_layer_address && !memcmp(&message->source,
1133 &iface->link_local, sizeof(message->source))) {
1134 INFO("dropping router solicitation sent from this host.");
1135 return;
1136 }
1137 }
1138 }
1139 interface = message->interface;
1140
1141 // Schedule an immediate send, which will be delayed by up to a second.
1142 if (!interface->ineligible && !interface->inactive) {
1143 interface_beacon_schedule(interface, 0);
1144 }
1145
1146 // When we receive a router solicit, it means that a host is looking for a router. We should
1147 // expect to hear replies if they are multicast. If we hear no replies, it could mean there is
1148 // no on-link prefix. In this case, we restart our own router discovery process. There is no
1149 // need to do this if we are the one advertising a prefix.
1150 start_vicarious_router_discovery_if_appropriate(interface);
1151 }
1152
1153 static void
1154 router_advertisement(icmp_message_t *message)
1155 {
1156 interface_t *iface;
1157 icmp_message_t *router, **rp;
1158 if (message->hop_limit != 255 || message->code != 0 || !IN6_IS_ADDR_LINKLOCAL(&message->source)) {
1159 ERROR("Invalid router advertisement, hop limit = %d, code = %d", message->hop_limit, message->code);
1160 icmp_message_free(message);
1161 return;
1162 }
1163 for (iface = interfaces; iface != NULL; iface = iface->next) {
1164 if (iface->have_link_layer_address && !memcmp(&message->source,
1165 &iface->link_local, sizeof(message->source))) {
1166 INFO("dropping router advertisement sent from this host.");
1167 icmp_message_free(message);
1168 return;
1169 }
1170 }
1171
1172 // See if we've had other advertisements from this router.
1173 for (rp = &message->interface->routers; *rp != NULL; rp = &(*rp)->next) {
1174 router = *rp;
1175 if (!memcmp(&router->source, &message->source, sizeof(message->source))) {
1176 message->next = router->next;
1177 *rp = message;
1178 icmp_message_free(router);
1179 break;
1180 }
1181 }
1182 // If not, save it.
1183 if (*rp == NULL) {
1184 *rp = message;
1185 }
1186
1187 // Something may have changed, so do a policy recalculation for this interface
1188 routing_policy_evaluate(message->interface, false);
1189 }
1190
1191 static void
1192 icmp_callback(io_t *NONNULL io, void *__unused context)
1193 {
1194 ssize_t rv;
1195 uint8_t icmp_buf[1500];
1196 unsigned offset = 0, length = 0;
1197 uint32_t reserved32;
1198 int ifindex;
1199 addr_t src, dest;
1200 interface_t *interface;
1201 int hop_limit;
1202
1203 rv = ioloop_recvmsg(io->fd, &icmp_buf[0], sizeof(icmp_buf), &ifindex, &hop_limit, &src, &dest);
1204 if (rv < 0) {
1205 ERROR("icmp_callback: can't read ICMP message: " PUB_S_SRP, strerror(errno));
1206 return;
1207 }
1208
1209 icmp_message_t *message = calloc(1, sizeof(*message));
1210 if (message == NULL) {
1211 ERROR("Unable to allocate icmp_message_t for parsing");
1212 return;
1213 }
1214
1215 message->source = src.sin6.sin6_addr;
1216 message->destination = dest.sin6.sin6_addr;
1217 message->hop_limit = hop_limit;
1218 for (interface = interfaces; interface; interface = interface->next) {
1219 if (interface->index == ifindex) {
1220 message->interface = interface;
1221 break;
1222 }
1223 }
1224 message->received_time = ioloop_timenow();
1225 message->received_time_already_adjusted = false;
1226 message->new_router = true;
1227
1228 if (message->interface == NULL) {
1229 SEGMENTED_IPv6_ADDR_GEN_SRP(message->source.s6_addr, src_buf);
1230 SEGMENTED_IPv6_ADDR_GEN_SRP(message->destination.s6_addr, dst_buf);
1231 INFO("ICMP message type %d from " PRI_SEGMENTED_IPv6_ADDR_SRP " to " PRI_SEGMENTED_IPv6_ADDR_SRP
1232 " on interface index %d, which isn't listed.",
1233 icmp_buf[0], SEGMENTED_IPv6_ADDR_PARAM_SRP(message->source.s6_addr, src_buf),
1234 SEGMENTED_IPv6_ADDR_PARAM_SRP(message->destination.s6_addr, dst_buf), ifindex);
1235 icmp_message_free(message);
1236 return;
1237 }
1238
1239 length = (unsigned)rv;
1240 if (length < sizeof (struct icmp6_hdr)) {
1241 ERROR("Short ICMP message: length %zd is shorter than ICMP header length %zd", rv, sizeof(struct icmp6_hdr));
1242 icmp_message_free(message);
1243 return;
1244 }
1245
1246 // The increasingly innaccurately named dns parse functions will work fine for this.
1247 if (!dns_u8_parse(icmp_buf, length, &offset, &message->type)) {
1248 goto out;
1249 }
1250 if (!dns_u8_parse(icmp_buf, length, &offset, &message->code)) {
1251 goto out;
1252 }
1253 // XXX check the checksum
1254 if (!dns_u16_parse(icmp_buf, length, &offset, &message->checksum)) {
1255 goto out;
1256 }
1257 switch(message->type) {
1258 case icmp_type_router_advertisement:
1259 if (!dns_u8_parse(icmp_buf, length, &offset, &message->cur_hop_limit)) {
1260 goto out;
1261 }
1262 if (!dns_u8_parse(icmp_buf, length, &offset, &message->flags)) {
1263 goto out;
1264 }
1265 if (!dns_u16_parse(icmp_buf, length, &offset, &message->router_lifetime)) {
1266 goto out;
1267 }
1268 if (!dns_u32_parse(icmp_buf, length, &offset, &message->reachable_time)) {
1269 goto out;
1270 }
1271 if (!dns_u32_parse(icmp_buf, length, &offset, &message->retransmission_timer)) {
1272 goto out;
1273 }
1274
1275 if (!icmp_message_parse_options(message, icmp_buf, length, &offset)) {
1276 goto out;
1277 }
1278 icmp_message_dump(message, &message->source, &message->destination);
1279 router_advertisement(message);
1280 // router_advertisement() is ressponsible for freeing the messaage if it doesn't need it.
1281 return;
1282 break;
1283
1284 case icmp_type_router_solicitation:
1285 if (!dns_u32_parse(icmp_buf, length, &offset, &reserved32)) {
1286 goto out;
1287 }
1288 if (!icmp_message_parse_options(message, icmp_buf, length, &offset)) {
1289 goto out;
1290 }
1291 icmp_message_dump(message, &message->source, &message->destination);
1292 router_solicit(message);
1293 break;
1294 case icmp_type_neighbor_advertisement:
1295 case icmp_type_neighbor_solicitation:
1296 case icmp_type_echo_request:
1297 case icmp_type_echo_reply:
1298 case icmp_type_redirect:
1299 break;
1300 }
1301
1302 out:
1303 icmp_message_free(message);
1304 return;
1305 }
1306
1307 #ifdef MONITOR_ROUTING_SOCKET
1308 static void
1309 route_message(io_t *__unused rt, route_message_t *message)
1310 {
1311 addr_t *addr;
1312
1313 switch(message->route.rtm_type) {
1314 // When an interface goes up, or when an address is added, we get one of these.
1315 case RTM_NEWADDR:
1316 INFO("Message length %d, version %d, type RTM_NEWADDR, index %d",
1317 message->len, message->route.rtm_version, message->address.ifam_index);
1318 // ifa_msghdr followed by zero or more addresses
1319 // Addresses start on 32-bit boundaries and are sockaddrs with sa_len indicating the size.
1320 addr = (addr_t *)((&message->address) + 1);
1321 break;
1322 // When an interface goes down, we may get one of these. Also when an address is deleted for some reason.
1323 case RTM_DELADDR:
1324 INFO("Message length %d, version %d, type RTM_DELADDR, index %d",
1325 message->len, message->route.rtm_version, message->address.ifam_index);
1326 // ifa_msghdr followed by zero or more addresses
1327 addr = (addr_t *)((&message->address) + 1);
1328 break;
1329 // When an interface goes up or down, we get one of these.
1330 case RTM_IFINFO:
1331 INFO("Message length %d, version %d, type RTM_IFINFO, index %d",
1332 message->len, message->route.rtm_version, message->interface.ifm_index);
1333 // if_msghdr followed by zero or more addresses
1334 addr = (addr_t *)((&message->interface) + 1);
1335 break;
1336 case RTM_IFINFO2:
1337 INFO("Message length %d, version %d, type RTM_IFINFO2, index %d",
1338 message->len, message->route.rtm_version, message->if2.ifm_index);
1339 addr = (addr_t *)((&message->if2) + 1);
1340 break;
1341 case RTM_ADD:
1342 INFO("Message length %d, version %d, type RTM_ADD, index %d",
1343 message->len, message->route.rtm_version, message->if2.ifm_index);
1344 addr = (addr_t *)((&message->if2) + 1);
1345 break;
1346 case RTM_DELETE:
1347 INFO("Message length %d, version %d, type RTM_DELETE, index %d",
1348 message->len, message->route.rtm_version, message->if2.ifm_index);
1349 addr = (addr_t *)((&message->if2) + 1);
1350 break;
1351 case RTM_CHANGE:
1352 INFO("Message length %d, version %d, type RTM_CHANGE, index %d",
1353 message->len, message->route.rtm_version, message->if2.ifm_index);
1354 addr = (addr_t *)((&message->if2) + 1);
1355 break;
1356 default:
1357 INFO("Message length %d, version %d, type %d", message->len, message->route.rtm_version,
1358 message->route.rtm_type);
1359 break;
1360 }
1361 return;
1362 }
1363
1364 static void
1365 route_callback(io_t *NONNULL io, void *__unused context)
1366 {
1367 ssize_t rv;
1368 route_message_t message;
1369
1370 rv = read(io->fd, &message, sizeof message);
1371 if (rv < 0) {
1372 ERROR("route_callback: read returned " PUB_S_SRP, strerror(errno));
1373 ioloop_close(io);
1374 return;
1375 } else if (rv == 0) {
1376 ERROR("route_callback: read returned 0");
1377 ioloop_close(io);
1378 return;
1379 } else {
1380 // Process the message.
1381 route_message(io, &message);
1382 return;
1383 }
1384 }
1385
1386 static void
1387 route_entry(struct rt_msghdr2 *route)
1388 {
1389 (void)route;
1390 }
1391
1392 static void
1393 route_fetch(void)
1394 {
1395 size_t table_size;
1396 #define NUM_SYSCTL_ARGS 6
1397 int sysctl_args[NUM_SYSCTL_ARGS];
1398 char *table, *next_route, *end;
1399 struct rt_msghdr2 *route;
1400 int rv;
1401
1402 sysctl_args[0] = CTL_NET;
1403 sysctl_args[1] = PF_ROUTE;
1404 sysctl_args[2] = 0;
1405 sysctl_args[3] = 0;
1406 sysctl_args[4] = NET_RT_DUMP2;
1407 sysctl_args[5] = 0;
1408
1409 rv = sysctl(sysctl_args, NUM_SYSCTL_ARGS, NULL, &table_size, NULL, 0);
1410 if (rv < 0) {
1411 ERROR("route_fetch: sysctl failed getting routing table dump estimate: " PUB_S_SRP, strerror(errno));
1412 return;
1413 }
1414
1415 table = malloc(table_size);
1416 if (table == NULL) {
1417 ERROR("No memory for routing table of size %zu", table_size);
1418 return;
1419 }
1420
1421 rv = sysctl(sysctl_args, NUM_SYSCTL_ARGS, table, &table_size, NULL, 0);
1422 if (rv < 0) {
1423 ERROR("route_fetch: sysctl failed getting routing table dump: " PUB_S_SRP, strerror(errno));
1424 return;
1425 }
1426
1427 end = table + table_size;
1428 for (next_route = table; next_route < end; next_route = next_route + route->rtm_msglen) {
1429 route = (struct rt_msghdr2 *)next_route;
1430 if (route->rtm_msglen + next_route > end) {
1431 INFO("Bogus routing table--last route goes past end of buffer.");
1432 break;
1433 }
1434 route_entry(route);
1435 }
1436 }
1437
1438 bool
1439 start_route_listener(void)
1440 {
1441 int sock = socket(PF_ROUTE, SOCK_RAW, AF_INET);
1442 if (sock < 0) {
1443 ERROR("Unable to listen for link status change events: " PUB_S_SRP, strerror(errno));
1444 return false;
1445 }
1446
1447 io_t *io = ioloop_file_descriptor_create(sock, NULL, NULL);
1448 if (io == NULL) {
1449 ERROR("No memory for route I/O structure.");
1450 close(sock);
1451 return false;
1452 }
1453
1454 #ifdef RO_MSGFILTER
1455 static uint8_t subscriptions[] = { RTM_NEWADDR, RTM_DELADDR, RTM_IFINFO, RTM_IFINFO2 };
1456 if (setsockopt(routefd, PF_ROUTE, RO_MSGFILTER, &subscriptions, (socklen_t)sizeof(subscriptions)) < 0) {
1457 ERROR("Unable to set routing socket subscriptions.");
1458 }
1459 #endif
1460
1461 ioloop_add_reader(io, route_callback);
1462
1463 route_fetch();
1464 return true;
1465 }
1466 #endif // MONITOR_ROUTING_SOCKET
1467
1468 #if defined(USE_IPCONFIGURATION_SERVICE)
1469 static void
1470 dict_add_string_as_array(CFMutableDictionaryRef dict, CFStringRef prop_name, const char * str)
1471 {
1472 CFArrayRef array;
1473 CFStringRef prop_val;
1474
1475 if (str == NULL) {
1476 return;
1477 }
1478 prop_val = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
1479 array = CFArrayCreate(NULL, (const void **)&prop_val, 1, &kCFTypeArrayCallBacks);
1480 CFRelease(prop_val);
1481 CFDictionarySetValue(dict, prop_name, array);
1482 CFRelease(array);
1483 return;
1484 }
1485
1486 static void
1487 dict_add_int_as_array(CFMutableDictionaryRef dict, CFStringRef prop_name,
1488 int int_val)
1489 {
1490 CFArrayRef array;
1491 CFNumberRef num;
1492
1493 num = CFNumberCreate(NULL, kCFNumberIntType, &int_val);
1494 array = CFArrayCreate(NULL, (const void **)&num, 1, &kCFTypeArrayCallBacks);
1495 CFRelease(num);
1496 CFDictionarySetValue(dict, prop_name, array);
1497 CFRelease(array);
1498 return;
1499 }
1500
1501 static CFDictionaryRef
1502 ipconfig_options_dict_create(CFDictionaryRef config_dict)
1503 {
1504 return CFDictionaryCreate(NULL, (const void **)&kIPConfigurationServiceOptionIPv6Entity,
1505 (const void **)&config_dict, 1, &kCFTypeDictionaryKeyCallBacks,
1506 &kCFTypeDictionaryValueCallBacks);
1507 }
1508
1509 static void
1510 ipconfig_service_changed(interface_t * interface)
1511 {
1512 CFDictionaryRef service_info;
1513
1514 if (interface->ip_configuration_service == NULL) {
1515 INFO("ipconfig_service_changed: ip_configuration_service is NULL");
1516 return;
1517 }
1518 service_info = IPConfigurationServiceCopyInformation(interface->ip_configuration_service);
1519 if (service_info == NULL) {
1520 INFO("ipconfig_service_changed: IPConfigurationService on " PUB_S_SRP " is incomplete", interface->name);
1521 }
1522 else {
1523 INFO("ipconfig_service_changed: IPConfigurationService on " PUB_S_SRP " is ready", interface->name);
1524 CFRelease(service_info);
1525
1526 // Now that the prefix is configured on the interface, we can start advertising it.
1527 interface->on_link_prefix_configured = true;
1528 routing_policy_evaluate(interface, true);
1529 }
1530 return;
1531
1532 }
1533
1534
1535 static void
1536 ipconfig_service_callback(SCDynamicStoreRef __unused session, CFArrayRef __unused changes,
1537 void * info)
1538 {
1539 interface_t * interface = (interface_t *)info;
1540
1541 ipconfig_service_changed(interface);
1542 return;
1543 }
1544
1545 static void
1546 monitor_ipconfig_service(interface_t * interface)
1547 {
1548 SCDynamicStoreContext context = {
1549 .version = 0,
1550 .info = NULL,
1551 .retain = NULL,
1552 .release = NULL,
1553 .copyDescription = NULL
1554 };
1555 CFArrayRef keys;
1556 SCDynamicStoreRef store;
1557 CFStringRef store_key;
1558
1559 if (interface->ip_configuration_store != NULL) {
1560 INFO("Releasing old SCDynamicStore object for " PUB_S_SRP, interface->name);
1561 SCDynamicStoreSetDispatchQueue(interface->ip_configuration_store, NULL);
1562 CFRelease(interface->ip_configuration_store);
1563 interface->ip_configuration_store = NULL;
1564 }
1565
1566 #define OUR_IDENTIFIER CFSTR("ThreadBorderRouter")
1567 context.info = interface;
1568 store = SCDynamicStoreCreate(NULL, OUR_IDENTIFIER,
1569 ipconfig_service_callback, &context);
1570 store_key = IPConfigurationServiceGetNotificationKey(interface->ip_configuration_service);
1571 keys = CFArrayCreate(NULL, (const void * *)&store_key,
1572 1,
1573 &kCFTypeArrayCallBacks);
1574 SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1575 CFRelease(keys);
1576
1577 /* avoid race with being notified */
1578 ipconfig_service_changed(interface);
1579 SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue());
1580 interface->ip_configuration_store = (void *)store;
1581 }
1582
1583 static Boolean
1584 start_ipconfig_service(interface_t *interface, const char *ip6addr_str)
1585 {
1586 CFMutableDictionaryRef config_dict;
1587 CFStringRef interface_name;
1588 CFDictionaryRef options;
1589
1590 if (interface->ip_configuration_service != NULL) {
1591 INFO("start_ipconfig_service: releasing old IPConfigurationService object for " PUB_S_SRP, interface->name);
1592 CFRelease(interface->ip_configuration_service);
1593 interface->ip_configuration_service = NULL;
1594 }
1595
1596 // Create an IPv6 entity dictionary with ConfigMethod, Addresses, and PrefixLength properties
1597 config_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1598 CFDictionarySetValue(config_dict, kSCPropNetIPv6ConfigMethod, kSCValNetIPv6ConfigMethodManual);
1599 #define PREFIX_LENGTH 64
1600 dict_add_string_as_array(config_dict, kSCPropNetIPv6Addresses, ip6addr_str);
1601 dict_add_int_as_array(config_dict, kSCPropNetIPv6PrefixLength, PREFIX_LENGTH);
1602 options = ipconfig_options_dict_create(config_dict);
1603 CFRelease(config_dict);
1604 interface_name = CFStringCreateWithCString(NULL, interface->name, kCFStringEncodingUTF8);
1605 interface->ip_configuration_service = IPConfigurationServiceCreate(interface_name, options);
1606 CFRelease(interface_name);
1607 CFRelease(options);
1608 if (interface->ip_configuration_service == NULL) {
1609 ERROR("start_ipconfig_service: IPConfigurationServiceCreate on " PUB_S_SRP " failed", interface->name);
1610 }
1611 else {
1612 monitor_ipconfig_service(interface);
1613 struct in6_addr ip6addr;
1614 int ret = inet_pton(AF_INET6, ip6addr_str, ip6addr.s6_addr);
1615 if (ret == 1) {
1616 SEGMENTED_IPv6_ADDR_GEN_SRP(ip6addr.s6_addr, ip6addr_buf);
1617 INFO("start_ipconfig_service: IPConfigurationServiceCreate on " PRI_S_SRP "/" PRI_SEGMENTED_IPv6_ADDR_SRP
1618 " succeeded", interface->name, SEGMENTED_IPv6_ADDR_PARAM_SRP(ip6addr.s6_addr, ip6addr_buf));
1619 }
1620 }
1621 return (interface->ip_configuration_service != NULL);
1622 }
1623
1624 #elif defined(CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG)
1625 static void
1626 link_route_done(void *context, int status, const char *error)
1627 {
1628 interface_t *interface = context;
1629
1630 if (error != NULL) {
1631 ERROR("link_route_done on " PUB_S_SRP ": " PUB_S_SRP, interface->name, error);
1632 } else {
1633 INFO("link_route_done on " PUB_S_SRP ": %d.", interface->name, status);
1634 }
1635 ioloop_subproc_release(link_route_adder_process);
1636 // Now that the on-link prefix is configured, time for a policy re-evaluation.
1637 interface->on_link_prefix_configured = true;
1638 routing_policy_evaluate(interface, true);
1639 }
1640 #endif
1641
1642 static void
1643 interface_prefix_configure(struct in6_addr prefix, interface_t *interface)
1644 {
1645 int sock;
1646
1647 sock = socket(PF_INET6, SOCK_DGRAM, 0);
1648 if (sock < 0) {
1649 ERROR("interface_prefix_configure: socket(PF_INET6, SOCK_DGRAM, 0) failed " PUB_S_SRP ": " PUB_S_SRP,
1650 interface->name, strerror(errno));
1651 return;
1652 }
1653 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
1654 struct in6_addr interface_address = prefix;
1655 char addrbuf[INET6_ADDRSTRLEN];
1656 interface_address.s6_addr[15] = 1;
1657 inet_ntop(AF_INET6, &interface_address, addrbuf, INET6_ADDRSTRLEN);
1658 #if defined (USE_IPCONFIGURATION_SERVICE)
1659 if (!start_ipconfig_service(interface, addrbuf)) {
1660 close(sock);
1661 return;
1662 }
1663 #elif defined(CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG)
1664 char *args[] = { "set", interface->name, "MANUAL-V6", addrbuf, "64" };
1665
1666 INFO("interface_prefix_configure: /sbin/ipconfig " PUB_S_SRP " " PUB_S_SRP " " PUB_S_SRP " " PUB_S_SRP " "
1667 PUB_S_SRP, args[0], args[1], args[2], args[3], args[4]);
1668 link_route_adder_process = ioloop_subproc("/usr/sbin/ipconfig", args, 5, link_route_done, interface, NULL);
1669 if (link_route_adder_process == NULL) {
1670 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address.s6_addr, if_addr_buf);
1671 ERROR("interface_prefix_configure: unable to set interface address for " PUB_S_SRP " to "
1672 PRI_SEGMENTED_IPv6_ADDR_SRP ".", interface->name,
1673 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address.s6_addr, if_addr_buf));
1674 }
1675 #else
1676 struct in6_aliasreq alias_request;
1677 memset(&alias_request, 0, sizeof(alias_request));
1678 strlcpy(alias_request.ifra_name, interface->name, IFNAMSIZ);
1679 alias_request.ifra_addr.sin6_family = AF_INET6;
1680 alias_request.ifra_addr.sin6_len = sizeof(alias_request.ifra_addr);
1681 memcpy(&alias_request.ifra_addr.sin6_addr, &interface_address, sizeof(alias_request.ifra_addr.sin6_addr));
1682 alias_request.ifra_prefixmask.sin6_len = sizeof(alias_request.ifra_addr);
1683 alias_request.ifra_prefixmask.sin6_family = AF_INET6;
1684 memset(&alias_request.ifra_prefixmask.sin6_addr, 0xff, 8); // /64.
1685 alias_request.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; // seconds, I hope?
1686 alias_request.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; // seconds, I hope?
1687 ret = ioctl(sock, SIOCAIFADDR_IN6, &alias_request);
1688 if (ret < 0) {
1689 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address.s6_addr, if_addr_buf);
1690 ERROR("interface_prefix_configure: can't configure static address " PRI_SEGMENTED_IPv6_ADDR_SRP " on " PUB_S_SRP
1691 ": " PUB_S_SRP, SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address.s6_addr, if_addr_buf), interface->name,
1692 strerror(errno));
1693 } else {
1694 SEGMENTED_IPv6_ADDR_GEN_SRP(interface_address.s6_addr, if_addr_buf);
1695 INFO("interface_prefix_configure: added address " PRI_SEGMENTED_IPv6_ADDR_SRP " to " PUB_S_SRP,
1696 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface_address.s6_addr, if_addr_buf), interface->name);
1697 }
1698 #endif // CONFIGURE_STATIC_INTERFACE_ADDRESSES_WITH_IPCONFIG
1699 #else
1700 (void)prefix;
1701 #endif // CONFIGURE_STATIC_INTERFACE_ADDRESSES
1702 }
1703
1704 #ifdef USE_SYSCTL_COMMMAND_TO_ENABLE_FORWARDING
1705 static void
1706 thread_forwarding_done(void *__unused context, int status, const char *error)
1707 {
1708 if (error != NULL) {
1709 ERROR("thread_forwarding_done: " PUB_S_SRP, error);
1710 } else {
1711 INFO("thread_forwarding_done: %d.", status);
1712 }
1713 ioloop_subproc_release(thread_forwarding_setter_process);
1714 }
1715
1716 static void
1717 set_thread_forwarding(void)
1718 {
1719 char *args[] = { "-w", "net.inet6.ip6.forwarding=1" };
1720
1721 INFO("/usr/sbin/sysctl " PUB_S_SRP " " PUB_S_SRP, args[0], args[1]);
1722 thread_forwarding_setter_process = ioloop_subproc("/usr/sbin/sysctl", args, 2, thread_forwarding_done,
1723 NULL, NULL);
1724 if (thread_forwarding_setter_process == NULL) {
1725 ERROR("Unable to set thread forwarding enabled.");
1726 }
1727 }
1728
1729 #else
1730
1731 static void
1732 set_thread_forwarding(void)
1733 {
1734 int wun = 1;
1735 int ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &wun, sizeof(wun));
1736 if (ret < 0) {
1737 ERROR("set_thread_forwarding: " PUB_S_SRP, strerror(errno));
1738 } else {
1739 INFO("Enabled IPv6 forwarding.");
1740 }
1741 }
1742 #endif // USE_SYSCTL_COMMMAND_TO_ENABLE_FORWARDING
1743
1744 #ifdef NEED_THREAD_RTI_SETTER
1745 static void
1746 thread_rti_done(void *__unused context, int status, const char *error)
1747 {
1748 if (error != NULL) {
1749 ERROR("thread_rti_done: " PUB_S_SRP, error);
1750 } else {
1751 INFO("thread_rti_done: %d.", status);
1752 }
1753 ioloop_subproc_release(thread_rti_setter_process);
1754 }
1755
1756 static void
1757 set_thread_rti(void)
1758 {
1759 char *args[] = { "-w", "net.inet6.icmp6.nd6_process_rti=1" };
1760 thread_rti_setter_process = ioloop_subproc("/usr/sbin/sysctl", args, 2, thread_rti_done,
1761 NULL, NULL);
1762 if (thread_rti_setter_process == NULL) {
1763 ERROR("Unable to set thread rti enabled.");
1764 }
1765 }
1766 #endif
1767
1768 #if TARGET_OS_TV && !defined(RA_TESTER)
1769 #ifdef ADD_PREFIX_WITH_WPANCTL
1770 static void
1771 thread_prefix_done(void *__unused context, int status, const char *error)
1772 {
1773 if (error != NULL) {
1774 ERROR("thread_prefix_done: " PUB_S_SRP, error);
1775 } else {
1776 interface_t *interface;
1777
1778 INFO("thread_prefix_done: %d.", status);
1779 for (interface = interfaces; interface; interface = interface->next) {
1780 if (!interface->inactive) {
1781 interface_beacon_schedule(interface, 0);
1782 }
1783 }
1784 }
1785 ioloop_subproc_release(thread_prefix_adder_process);
1786 }
1787 #endif
1788
1789 static void
1790 cti_add_prefix_callback(void *__unused context, cti_status_t status)
1791 {
1792 interface_t *interface;
1793 INFO("cti_add_prefix_callback: %d", status);
1794 for (interface = interfaces; interface; interface = interface->next) {
1795 if (!interface->inactive) {
1796 interface_beacon_schedule(interface, 0);
1797 }
1798 }
1799 }
1800
1801 static thread_prefix_t *
1802 get_advertised_thread_prefix(void)
1803 {
1804 if (published_thread_prefix != NULL) {
1805 return published_thread_prefix;
1806 } else {
1807 return adopted_thread_prefix;
1808 }
1809 return NULL;
1810 }
1811
1812 static void
1813 set_thread_prefix(void)
1814 {
1815 char addrbuf[INET6_ADDRSTRLEN];
1816 thread_prefix_t *advertised_thread_prefix = get_advertised_thread_prefix();
1817 if (advertised_thread_prefix == NULL) {
1818 ERROR("set_thread_prefix: no advertised thread prefix.");
1819 return;
1820 }
1821 SEGMENTED_IPv6_ADDR_GEN_SRP(advertised_thread_prefix->prefix.s6_addr, thread_prefix_buf);
1822 inet_ntop(AF_INET6, &advertised_thread_prefix->prefix, addrbuf, sizeof addrbuf);
1823 #ifdef ADD_PREFIX_WITH_WPANCTL
1824 char *args[] = { "add-prefix", "--stable", "--preferred", "--slaac", "--default-route", "--on-mesh", addrbuf };
1825 INFO("/usr/local/bin/wpanctl " PUB_S_SRP " " PUB_S_SRP " " PUB_S_SRP " " PUB_S_SRP " " PUB_S_SRP " " PUB_S_SRP " "
1826 PRI_SEGMENTED_IPv6_ADDR_SRP, args[0], args[1], args[2], args[3], args[4], args[5],
1827 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix->prefix.s6_addr, thread_prefix_buf));
1828 thread_prefix_adder_process = ioloop_subproc("/usr/local/bin/wpanctl", args, 7, thread_prefix_done,
1829 NULL, NULL);
1830 if (thread_prefix_adder_process == NULL) {
1831 ERROR("Unable to add thread interface prefix.");
1832 }
1833 #else
1834 INFO("add_prefix(true, true, true, true, " PRI_SEGMENTED_IPv6_ADDR_SRP ")",
1835 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix->prefix.s6_addr, thread_prefix_buf));
1836 int status = cti_add_prefix(NULL, cti_add_prefix_callback, dispatch_get_main_queue(),
1837 &advertised_thread_prefix->prefix, advertised_thread_prefix->prefix_len,
1838 true, true, true, true);
1839 if (status) {
1840 ERROR("Unable to add thread interface prefix.");
1841 }
1842 #endif
1843 }
1844 #endif // TARGET_OS_TV && !RA_TESTER
1845
1846 static void
1847 router_advertisement_send(interface_t *interface)
1848 {
1849 uint8_t *message;
1850 dns_towire_state_t towire;
1851
1852 // Thread blocks RAs so no point sending them.
1853 if (interface->inactive
1854 #ifndef RA_TESTER
1855 || interface->is_thread
1856 #endif
1857 ) {
1858 return;
1859 }
1860
1861 #define MAX_ICMP_MESSAGE 1280
1862 message = malloc(MAX_ICMP_MESSAGE);
1863 if (message == NULL) {
1864 ERROR("Unable to construct ICMP Router Advertisement: no memory");
1865 return;
1866 }
1867
1868 // Construct the ICMP header and options for each interface.
1869 memset(&towire, 0, sizeof towire);
1870 towire.p = message;
1871 towire.lim = message + MAX_ICMP_MESSAGE;
1872
1873 // Construct the ICMP header.
1874 // We use the DNS message construction functions because it's easy; probably should just make
1875 // the towire functions more generic.
1876 dns_u8_to_wire(&towire, ND_ROUTER_ADVERT); // icmp6_type
1877 dns_u8_to_wire(&towire, 0); // icmp6_code
1878 dns_u16_to_wire(&towire, 0); // The kernel computes the checksum (we don't technically have it).
1879 dns_u8_to_wire(&towire, 0); // Hop limit, we don't set.
1880 dns_u8_to_wire(&towire, 0); // Flags. We don't offer DHCP, so We set neither the M nor the O bit.
1881 // We are not a home agent, so no H bit. Lifetime is 0, so Prf is 0.
1882 #ifdef ROUTER_LIFETIME_HACK
1883 dns_u16_to_wire(&towire, 1800); // Router lifetime, hacked. This shouldn't ever be enabled.
1884 #else
1885 #ifdef RA_TESTER
1886 // Advertise a default route on the simulated thread network
1887 if (!strcmp(interface->name, thread_interface_name)) {
1888 dns_u16_to_wire(&towire, 1800); // Router lifetime for default route
1889 } else {
1890 #endif
1891 dns_u16_to_wire(&towire, 0); // Router lifetime for non-default default route(s).
1892 #ifdef RA_TESTER
1893 }
1894 #endif // RA_TESTER
1895 #endif // ROUTER_LIFETIME_HACK
1896 dns_u32_to_wire(&towire, 0); // Reachable time for NUD, we have no opinion on this.
1897 dns_u32_to_wire(&towire, 0); // Retransmission timer, again we have no opinion.
1898
1899 // Send Source link-layer address option
1900 if (interface->have_link_layer_address) {
1901 dns_u8_to_wire(&towire, ND_OPT_SOURCE_LINKADDR);
1902 dns_u8_to_wire(&towire, 1); // length / 8
1903 dns_rdata_raw_data_to_wire(&towire, &interface->link_layer, sizeof(interface->link_layer));
1904 INFO("Advertising source lladdr " PRI_MAC_ADDR_SRP " on " PUB_S_SRP, MAC_ADDR_PARAM_SRP(interface->link_layer),
1905 interface->name);
1906 }
1907
1908 #ifndef RA_TESTER
1909 // Send MTU of 1280 for Thread?
1910 if (interface->is_thread) {
1911 dns_u8_to_wire(&towire, ND_OPT_MTU);
1912 dns_u8_to_wire(&towire, 1); // length / 8
1913 dns_u32_to_wire(&towire, 1280);
1914 INFO("Advertising MTU of 1280 on " PUB_S_SRP, interface->name);
1915 }
1916 #endif
1917
1918 // Send Prefix Information option if there's no IPv6 on the link.
1919 if (interface->advertise_ipv6_prefix) {
1920 dns_u8_to_wire(&towire, ND_OPT_PREFIX_INFORMATION);
1921 dns_u8_to_wire(&towire, 4); // length / 8
1922 dns_u8_to_wire(&towire, 64); // On-link prefix is always 64 bits
1923 dns_u8_to_wire(&towire, ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO); // On link, autoconfig
1924 dns_u32_to_wire(&towire, interface->valid_lifetime);
1925 dns_u32_to_wire(&towire, interface->preferred_lifetime);
1926 dns_u32_to_wire(&towire, 0); // Reserved
1927 dns_rdata_raw_data_to_wire(&towire, &interface->ipv6_prefix, sizeof interface->ipv6_prefix);
1928 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf);
1929 INFO("Advertising on-link prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " on " PUB_S_SRP,
1930 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf), interface->name);
1931 }
1932
1933 #ifndef ND_OPT_ROUTE_INFORMATION
1934 #define ND_OPT_ROUTE_INFORMATION 24
1935 #endif
1936 // In principle we can either send routes to links that are reachable by this router,
1937 // or just advertise a router to the entire ULA /48. In theory it doesn't matter
1938 // which we do; if we support HNCP at some point we probably need to be specific, but
1939 // for now being general is fine because we have no way to share a ULA.
1940 // Unfortunately, some RIO implementations do not work with specific routes, so for now
1941 // We are doing it the easy way and just advertising the /48.
1942 #define SEND_INTERFACE_SPECIFIC_RIOS 1
1943 #ifdef SEND_INTERFACE_SPECIFIC_RIOS
1944
1945 // If neither ROUTE_BETWEEN_NON_THREAD_LINKS nor RA_TESTER are defined, then we never want to
1946 // send an RIO other than for the thread network prefix.
1947 #if defined (ROUTE_BETWEEN_NON_THREAD_LINKS) || defined(RA_TESTER)
1948 interface_t *ifroute;
1949 // Send Route Information option for other interfaces.
1950 for (ifroute = interfaces; ifroute; ifroute = ifroute->next) {
1951 if (ifroute->inactive) {
1952 continue;
1953 }
1954 if (
1955 #ifndef RA_TESTER
1956 partition_can_provide_routing &&
1957 #endif
1958 ifroute->advertise_ipv6_prefix &&
1959 #ifdef SEND_ON_LINK_ROUTE
1960 // In theory we don't want to send RIO for the on-link prefix, but there's this bug, see.
1961 true &&
1962 #else
1963 ifroute != interface &&
1964 #endif
1965 #ifdef RA_TESTER
1966 // For the RA tester, we don't need to send an RIO to the thread network because we're the
1967 // default router for that network.
1968 strcmp(interface->name, thread_interface_name)
1969 #else
1970 true
1971 #endif
1972 )
1973 {
1974 dns_u8_to_wire(&towire, ND_OPT_ROUTE_INFORMATION);
1975 dns_u8_to_wire(&towire, 2); // length / 8
1976 dns_u8_to_wire(&towire, 64); // Interface prefixes are always 64 bits
1977 dns_u8_to_wire(&towire, 0); // There's no reason at present to prefer one Thread BR over another
1978 dns_u32_to_wire(&towire, 1800); // Route lifetime 1800 seconds (30 minutes)
1979 dns_rdata_raw_data_to_wire(&towire, &ifroute->ipv6_prefix, 8); // /64 requires 8 bytes.
1980 SEGMENTED_IPv6_ADDR_GEN_SRP(ifroute->ipv6_prefix.s6_addr, ipv6_prefix_buf);
1981 INFO("Sending route to " PRI_SEGMENTED_IPv6_ADDR_SRP "%%" PUB_S_SRP " on " PUB_S_SRP,
1982 SEGMENTED_IPv6_ADDR_PARAM_SRP(ifroute->ipv6_prefix.s6_addr, ipv6_prefix_buf),
1983 ifroute->name, interface->name);
1984 }
1985 }
1986 #endif // ROUTE_BETWEEN_NON_THREAD_LINKS || RA_TESTER
1987
1988 #ifndef RA_TESTER
1989 // Send route information option for thread prefix
1990 thread_prefix_t *advertised_thread_prefix = get_advertised_thread_prefix();
1991 if (advertised_thread_prefix != NULL) {
1992 dns_u8_to_wire(&towire, ND_OPT_ROUTE_INFORMATION);
1993 dns_u8_to_wire(&towire, 2); // length / 8
1994 dns_u8_to_wire(&towire, 64); // Interface prefixes are always 64 bits
1995 dns_u8_to_wire(&towire, 0); // There's no reason at present to prefer one Thread BR over another
1996 dns_u32_to_wire(&towire, 1800); // Route lifetime 1800 seconds (30 minutes)
1997 dns_rdata_raw_data_to_wire(&towire, &advertised_thread_prefix->prefix, 8); // /64 requires 8 bytes.
1998 SEGMENTED_IPv6_ADDR_GEN_SRP(advertised_thread_prefix->prefix.s6_addr, thread_prefix_buf);
1999 INFO("Sending route to " PRI_SEGMENTED_IPv6_ADDR_SRP "%%" PUB_S_SRP " on " PUB_S_SRP,
2000 SEGMENTED_IPv6_ADDR_PARAM_SRP(advertised_thread_prefix->prefix.s6_addr, thread_prefix_buf),
2001 thread_interface_name, interface->name);
2002 }
2003 #endif
2004 #else
2005 #ifndef SKIP_SLASH_48
2006 dns_u8_to_wire(&towire, ND_OPT_ROUTE_INFORMATION);
2007 dns_u8_to_wire(&towire, 3); // length / 8
2008 dns_u8_to_wire(&towire, 48); // ULA prefixes are always 48 bits
2009 dns_u8_to_wire(&towire, 0); // There's no reason at present to prefer one Thread BR over another
2010 dns_u32_to_wire(&towire, 1800); // Route lifetime 1800 seconds (30 minutes)
2011 dns_rdata_raw_data_to_wire(&towire, &ula_prefix, 16); // /48 requires 16 bytes
2012 #endif // SKIP_SLASH_48
2013 #endif // SEND_INTERFACE_SPECIFIC_RIOS
2014
2015 if (towire.error) {
2016 ERROR("No space in ICMP output buffer for " PUB_S_SRP " at route.c:%d", interface->name, towire.line);
2017 towire.error = 0;
2018 } else {
2019 icmp_send(message, towire.p - message, interface, &in6addr_linklocal_allnodes);
2020 }
2021 free(message);
2022 }
2023
2024 static void
2025 router_solicit_send(interface_t *interface)
2026 {
2027 uint8_t *message;
2028 dns_towire_state_t towire;
2029
2030 // Thread blocks RSs so no point sending them.
2031 if (interface->inactive
2032 #ifndef RA_TESTER
2033 || interface->is_thread
2034 #endif
2035 ) {
2036 return;
2037 }
2038
2039 #define MAX_ICMP_MESSAGE 1280
2040 message = malloc(MAX_ICMP_MESSAGE);
2041 if (message == NULL) {
2042 ERROR("Unable to construct ICMP Router Advertisement: no memory");
2043 return;
2044 }
2045
2046 // Construct the ICMP header and options for each interface.
2047 memset(&towire, 0, sizeof towire);
2048 towire.p = message;
2049 towire.lim = message + MAX_ICMP_MESSAGE;
2050
2051 // Construct the ICMP header.
2052 // We use the DNS message construction functions because it's easy; probably should just make
2053 // the towire functions more generic.
2054 dns_u8_to_wire(&towire, ND_ROUTER_SOLICIT); // icmp6_type
2055 dns_u8_to_wire(&towire, 0); // icmp6_code
2056 dns_u16_to_wire(&towire, 0); // The kernel computes the checksum (we don't technically have it).
2057 dns_u32_to_wire(&towire, 0); // Reserved32
2058
2059 // Send Source link-layer address option
2060 if (interface->have_link_layer_address) {
2061 dns_u8_to_wire(&towire, ND_OPT_SOURCE_LINKADDR);
2062 dns_u8_to_wire(&towire, 1); // length / 8
2063 dns_rdata_raw_data_to_wire(&towire, &interface->link_layer, sizeof(interface->link_layer));
2064 }
2065
2066 if (towire.error) {
2067 ERROR("No space in ICMP output buffer for " PUB_S_SRP " at route.c:%d", interface->name, towire.line);
2068 } else {
2069 icmp_send(message, towire.p - message, interface, &in6addr_linklocal_allrouters);
2070 }
2071 free(message);
2072 }
2073
2074 static void
2075 icmp_send(uint8_t *message, size_t length, interface_t *interface, const struct in6_addr *destination)
2076 {
2077 struct iovec iov;
2078 socklen_t cmsg_length = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof (int));
2079 uint8_t *cmsg_buffer;
2080 struct msghdr msg_header;
2081 struct cmsghdr *cmsg_pointer;
2082 struct in6_pktinfo *packet_info;
2083 int hop_limit = 255;
2084 ssize_t rv;
2085 struct sockaddr_in6 dest;
2086
2087 // Make space for the control message buffer.
2088 cmsg_buffer = malloc(cmsg_length);
2089 if (cmsg_buffer == NULL) {
2090 ERROR("Unable to construct ICMP Router Advertisement: no memory");
2091 return;
2092 }
2093
2094 // Send the message
2095 memset(&dest, 0, sizeof(dest));
2096 dest.sin6_family = AF_INET6;
2097 dest.sin6_scope_id = interface->index;
2098 dest.sin6_len = sizeof(dest);
2099 msg_header.msg_namelen = sizeof(dest);
2100 dest.sin6_addr = *destination;
2101
2102 msg_header.msg_name = &dest;
2103 iov.iov_base = message;
2104 iov.iov_len = length;
2105 msg_header.msg_iov = &iov;
2106 msg_header.msg_iovlen = 1;
2107 msg_header.msg_control = cmsg_buffer;
2108 msg_header.msg_controllen = cmsg_length;
2109
2110 // Specify the interface
2111 cmsg_pointer = CMSG_FIRSTHDR(&msg_header);
2112 cmsg_pointer->cmsg_level = IPPROTO_IPV6;
2113 cmsg_pointer->cmsg_type = IPV6_PKTINFO;
2114 cmsg_pointer->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
2115 packet_info = (struct in6_pktinfo *)CMSG_DATA(cmsg_pointer);
2116 memset(packet_info, 0, sizeof(*packet_info));
2117 packet_info->ipi6_ifindex = interface->index;
2118
2119 // Router advertisements and solicitations have a hop limit of 255
2120 cmsg_pointer = CMSG_NXTHDR(&msg_header, cmsg_pointer);
2121 cmsg_pointer->cmsg_level = IPPROTO_IPV6;
2122 cmsg_pointer->cmsg_type = IPV6_HOPLIMIT;
2123 cmsg_pointer->cmsg_len = CMSG_LEN(sizeof(int));
2124 memcpy(CMSG_DATA(cmsg_pointer), &hop_limit, sizeof(hop_limit));
2125
2126 // Send it
2127 rv = sendmsg(icmp_listener.io_state->fd, &msg_header, 0);
2128 if (rv < 0) {
2129 uint8_t *in6_addr_bytes = ((struct sockaddr_in6 *)(msg_header.msg_name))->sin6_addr.s6_addr;
2130 SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_bytes, in6_addr_buf);
2131 ERROR("icmp_send: sending " PUB_S_SRP " to " PRI_SEGMENTED_IPv6_ADDR_SRP " on interface " PUB_S_SRP
2132 " index %d: " PUB_S_SRP, message[0] == ND_ROUTER_SOLICIT ? "solicit" : "advertise",
2133 SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_bytes, in6_addr_buf),
2134 interface->name, interface->index, strerror(errno));
2135 } else if ((size_t)rv != iov.iov_len) {
2136 ERROR("icmp_send: short send to interface " PUB_S_SRP ": %zd < %zd", interface->name, rv, iov.iov_len);
2137 }
2138 free(cmsg_buffer);
2139 }
2140
2141 static void
2142 post_solicit_policy_evaluate(void *context)
2143 {
2144 interface_t *interface = context;
2145 INFO("Done waiting for router discovery to finish on " PUB_S_SRP, interface->name);
2146 interface->router_discovery_complete = true;
2147 interface->router_discovery_in_progress = false;
2148 flush_stale_routers(interface, ioloop_timenow());
2149
2150 // See if we need a new prefix on the interface.
2151 interface_prefix_evaluate(interface);
2152
2153 routing_policy_evaluate(interface, true);
2154 // Always clear out need_reconfigure_prefix when router_discovery_complete is set to true.
2155 interface->need_reconfigure_prefix = false;
2156 }
2157
2158 static void
2159 dump_network_signature(char *buffer, size_t buffer_size, const uint8_t *signature, long length)
2160 {
2161 char *hexp = buffer;
2162 int i;
2163 size_t left = buffer_size;
2164 size_t len;
2165
2166 if (length == 0) {
2167 strlcpy(buffer, "<NULL>", buffer_size);
2168 return;
2169 }
2170 for (i = 0; i < length; i++) {
2171 snprintf(hexp, left, "%02x", signature[i]);
2172 len = strlen(hexp);
2173 hexp += len;
2174 left -= len;
2175 }
2176 }
2177
2178 static void
2179 network_link_finalize(network_link_t *link)
2180 {
2181 if (link->signature != NULL) {
2182 free(link->signature);
2183 }
2184 free(link);
2185 }
2186
2187 #define network_link_create(signature, length) network_link_create_(signature, length, __FILE__, __LINE__);
2188 static network_link_t *
2189 network_link_create_(const uint8_t *signature, int length, const char *file, int line)
2190 {
2191 network_link_t *link = calloc(1, sizeof(*link));
2192 if (link != NULL) {
2193 if (signature != NULL) {
2194 if (length) {
2195 link->signature = malloc(length);
2196 if (link->signature == NULL) {
2197 INFO("network_link_create: no memory for signature.");
2198 free(link);
2199 return NULL;
2200 }
2201 memcpy(link->signature, signature, length);
2202 link->signature_length = length;
2203 }
2204 }
2205 RETAIN(link);
2206 }
2207 return link;
2208 }
2209
2210 static CFDictionaryRef
2211 network_link_dictionary_copy(network_link_t *link)
2212 {
2213 CFDictionaryRef dictionary = NULL;
2214 OSStatus err;
2215 err = CFPropertyListCreateFormatted(kCFAllocatorDefault, &dictionary,
2216 "{"
2217 "last-seen=%lli"
2218 "signature=%D"
2219 "prefix-number=%i"
2220 "}",
2221 link->last_seen,
2222 link->signature, (int)link->signature_length,
2223 link->prefix_number);
2224 if (err != 0) {
2225 dictionary = NULL;
2226 ERROR("CFPropertyListCreateFormatted failed: %d", err);
2227 }
2228 return dictionary;
2229 }
2230
2231 typedef struct network_link_parse_state network_link_parse_state_t;
2232 struct network_link_parse_state {
2233 network_link_t *NONNULL link;
2234 bool fail : 1;
2235 bool last_seen : 1;
2236 bool signature : 1;
2237 bool prefix_number : 1;
2238 };
2239
2240 static void
2241 network_link_parse(const void *key, const void *value, void *context)
2242 {
2243 network_link_parse_state_t *parse_state = context;
2244 int64_t last_seen;
2245
2246 if (parse_state->fail) {
2247 return;
2248 }
2249 if (CFGetTypeID(key) != CFStringGetTypeID()) {
2250 ERROR("network_link_parse: dictionary key not a string.");
2251 parse_state->fail = true;
2252 return;
2253 }
2254
2255 if (CFStringCompare(key, CFSTR("last-seen"), 0) == kCFCompareEqualTo) {
2256 // We store the last-seen time as a uint64 encoded as a string, because there is no uint64 CFNumber type.
2257 // We store the prefix-number time as a CFNumber because it's a uint16_t.
2258 if (CFGetTypeID(value) != CFNumberGetTypeID() ||
2259 !CFNumberGetValue(value, kCFNumberSInt64Type, &last_seen))
2260 {
2261 ERROR("network_link_parse: last-seen is not a valid CFNumber");
2262 parse_state->fail = true;
2263 } else {
2264 // For some reason CFNumber doesn't support uint64_t, but we are assuming that since we are copying this
2265 // unchanged, there will be no error introduced by this case.
2266 // CFProperyListCreateFormatted supports uint64_t, probably by doing the same thing.
2267 parse_state->link->last_seen = (uint64_t)last_seen;
2268 parse_state->last_seen = true;
2269 }
2270 } else if (CFStringCompare(key, CFSTR("signature"), 0) == kCFCompareEqualTo) {
2271 const uint8_t *data_buffer;
2272 long data_length;
2273
2274 // We store the signature as CFData.
2275 if (CFGetTypeID(value) != CFDataGetTypeID()) {
2276 ERROR("network_link_parse: Unable to get CFData for signature because it's not CFData.");
2277 parse_state->fail = true;
2278 } else {
2279 data_buffer = CFDataGetBytePtr(value);
2280 data_length = CFDataGetLength(value);
2281 if (data_length < 1) {
2282 parse_state->link->signature_length = 0;
2283 parse_state->link->signature = NULL;
2284 parse_state->signature = true;
2285 } else {
2286 parse_state->link->signature_length = data_length;
2287 parse_state->link->signature = malloc(data_length);
2288 if (parse_state->link->signature == NULL) {
2289 ERROR("network_link_parse: No memory for signature.");
2290 parse_state->fail = true;
2291 } else {
2292 memcpy(parse_state->link->signature, data_buffer, data_length);
2293 parse_state->signature = true;
2294 }
2295 }
2296 }
2297 } else if (CFStringCompare(key, CFSTR("prefix-number"), 0) == kCFCompareEqualTo) {
2298 // We store the prefix-number time as a CFNumber because it's a uint16_t.
2299 if (CFGetTypeID(value) != CFNumberGetTypeID() ||
2300 !CFNumberGetValue(value, kCFNumberSInt32Type, &parse_state->link->prefix_number))
2301 {
2302 ERROR("network_link_parse: prefix-number is not a valid CFNumber");
2303 parse_state->fail = true;
2304 } else if (parse_state->link->prefix_number < 0 || parse_state->link->prefix_number > UINT16_MAX) {
2305 ERROR("network_link_parse: Invalid prefix-number: %" PRIu32, parse_state->link->prefix_number);
2306 parse_state->fail = true;
2307 } else {
2308 parse_state->prefix_number = true;
2309 }
2310 } else {
2311 char key_buffer[64];
2312 if (!CFStringGetCString(key, key_buffer, sizeof(key_buffer), kCFStringEncodingUTF8)) {
2313 INFO("Unexpected network link element dictionary key, but can't decode key");
2314 } else {
2315 INFO("Unexpected network link element dictionary key " PUB_S_SRP, key_buffer);
2316 }
2317 parse_state->fail = true;
2318 }
2319 }
2320
2321 static void
2322 network_link_apply(const void *value, void *context)
2323 {
2324 bool *success = context;
2325 CFDictionaryRef values = value;
2326 network_link_parse_state_t parse_state;
2327 char hexbuf[60];
2328
2329 if (*success == false) {
2330 return;
2331 }
2332
2333 memset(&parse_state, 0, sizeof parse_state);
2334 parse_state.link = network_link_create(NULL, 0);
2335 if (parse_state.link == NULL) {
2336 ERROR("network_link_apply: no memory for link");
2337 *success = false;
2338 return;
2339 }
2340
2341 // Parse the dictionary into the structure.
2342 CFDictionaryApplyFunction(values, network_link_parse, &parse_state);
2343
2344 // Should have gotten three fields: last_seen, signature, prefix_number
2345 if (!parse_state.last_seen) {
2346 ERROR("network_link_apply: expecting last-seen");
2347 parse_state.fail = true;
2348 }
2349 if (!parse_state.signature) {
2350 ERROR("network_link_apply: expecting signature");
2351 parse_state.fail = true;
2352 }
2353 if (!parse_state.prefix_number) {
2354 ERROR("network_link_apply: expecting prefix-number");
2355 parse_state.fail = true;
2356 }
2357 if (parse_state.fail) {
2358 *success = false;
2359 RELEASE_HERE(parse_state.link, network_link_finalize);
2360 return;
2361 }
2362
2363 dump_network_signature(hexbuf, sizeof hexbuf, parse_state.link->signature, parse_state.link->signature_length);
2364
2365 // If the link signature hasn't been seen in over a week, there is no need to remember it. If no new links are
2366 // seen, an old signature could persist for much longer than a week, but this is okay--the goal here is to prevent
2367 // the link array from growing without bound, and whenver a link signature is added, the array is rewritte, at
2368 // which point the old link signatures will be erased.
2369 if (ioloop_timenow() - parse_state.link->last_seen > 1000 * 3600 * 24 * 7) {
2370 INFO("network_link_apply: discarding link signature " PRI_S_SRP
2371 ", prefix number %d, which is more than a week old", hexbuf, parse_state.link->prefix_number);
2372 RELEASE_HERE(parse_state.link, network_link_finalize);
2373 return;
2374 }
2375
2376 parse_state.link->next = network_links;
2377 network_links = parse_state.link;
2378 INFO("network_link_apply: parsed link signature " PRI_S_SRP ", prefix number %d", hexbuf,
2379 network_links->prefix_number);
2380 // This is a temporary fix to clean up bogus link prefixes that may exist in preferences.
2381 if (network_links->prefix_number == 0) {
2382 network_links->prefix_number = ula_serial++;
2383 } else {
2384 if (network_links->prefix_number >= ula_serial) {
2385 ula_serial = network_links->prefix_number + 1;
2386 }
2387 }
2388 }
2389
2390 static void
2391 network_link_record(network_link_t *link)
2392 {
2393 char hexbuf[60];
2394 CFDictionaryRef link_dictionary;
2395 if (network_link_array == NULL) {
2396 ERROR("network_link_record: no network_link_array, can't record new link.");
2397 return;
2398 }
2399 link_dictionary = network_link_dictionary_copy(link);
2400 if (link_dictionary == NULL) {
2401 ERROR("network_link_record: can't convert link into dictionary");
2402 return;
2403 }
2404 CFArrayAppendValue(network_link_array, link_dictionary);
2405
2406 CFPreferencesSetValue(CFSTR("network-links"), network_link_array,
2407 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2408 kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
2409 if (!CFPreferencesSynchronize(CFSTR("com.apple.srp-mdns-proxy.preferences"),
2410 kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)) {
2411 ERROR("network_link_record: CFPreferencesSynchronize: Unable to store network link array.");
2412 }
2413 CFRelease(link_dictionary);
2414 dump_network_signature(hexbuf, sizeof hexbuf, link->signature, link->signature_length);
2415 INFO("network_link_record: recording link signature " PRI_S_SRP ", prefix number %d", hexbuf, link->prefix_number);
2416 }
2417
2418 void
2419 ula_generate(void)
2420 {
2421 char ula_prefix_buffer[INET6_ADDRSTRLEN];
2422 struct in6_addr old_ula_prefix;
2423 bool prefix_changed;
2424
2425 // Already have a prefix?
2426 if (ula_prefix.s6_addr[0] == 0xfd) {
2427 old_ula_prefix = ula_prefix;
2428 prefix_changed = true;
2429 } else {
2430 prefix_changed = false;
2431 }
2432
2433 memset(&ula_prefix, 0, sizeof(ula_prefix));
2434 ula_prefix.s6_addr[0] = 0xfd;
2435 arc4random_buf(&ula_prefix.s6_addr[1], 5); // 40 bits of randomness
2436
2437 inet_ntop(AF_INET6, &ula_prefix, ula_prefix_buffer, sizeof ula_prefix_buffer);
2438 CFStringRef ula_string = CFStringCreateWithCString(NULL, ula_prefix_buffer, kCFStringEncodingUTF8);
2439 if (ula_string == NULL) {
2440 ERROR("ula_generate: unable to create a ULA prefix string to store in preferences.");
2441 } else {
2442 CFPreferencesSetValue(CFSTR("ula-prefix"), ula_string,
2443 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2444 kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
2445 if (!CFPreferencesSynchronize(CFSTR("com.apple.srp-mdns-proxy.preferences"),
2446 kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)) {
2447 ERROR("CFPreferencesSynchronize: Unable to store ULA prefix.");
2448 }
2449 CFRelease(ula_string);
2450 }
2451 if (prefix_changed) {
2452 SEGMENTED_IPv6_ADDR_GEN_SRP(old_ula_prefix.s6_addr, old_prefix_buf);
2453 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix.s6_addr, new_prefix_buf);
2454 INFO("ula-generate: prefix changed from " PRI_SEGMENTED_IPv6_ADDR_SRP " to " PRI_SEGMENTED_IPv6_ADDR_SRP,
2455 SEGMENTED_IPv6_ADDR_PARAM_SRP(old_ula_prefix.s6_addr, old_prefix_buf),
2456 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix.s6_addr, new_prefix_buf));
2457 } else {
2458 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix.s6_addr, new_prefix_buf);
2459 INFO("ula-generate: generated ULA prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
2460 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix.s6_addr, new_prefix_buf));
2461 }
2462
2463 // Set up the thread prefix.
2464 my_thread_prefix = ula_prefix;
2465 have_thread_prefix = true;
2466 }
2467
2468 static void
2469 ula_setup(void)
2470 {
2471 char ula_prefix_buffer[INET6_ADDRSTRLEN];
2472 bool have_stored_ula_prefix = false;
2473
2474 // Set up the ULA in case we need it.
2475 CFPropertyListRef plist = CFPreferencesCopyValue(CFSTR("ula-prefix"),
2476 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2477 kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
2478 if (plist != NULL) {
2479 if (CFGetTypeID(plist) == CFStringGetTypeID()) {
2480 if (CFStringGetCString((CFStringRef)plist, ula_prefix_buffer, sizeof(ula_prefix_buffer),
2481 kCFStringEncodingUTF8)) {
2482 if (inet_pton(AF_INET6, ula_prefix_buffer, &ula_prefix)) {
2483 SEGMENTED_IPv6_ADDR_GEN_SRP(ula_prefix.s6_addr, ula_prefix_buf);
2484 INFO("ula_setup: re-using stored prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
2485 SEGMENTED_IPv6_ADDR_PARAM_SRP(ula_prefix.s6_addr, ula_prefix_buf));
2486 have_stored_ula_prefix = true;
2487 }
2488 }
2489 }
2490 CFRelease(plist);
2491
2492 // Get the list of known network links (identified by network signature)
2493 plist = CFPreferencesCopyValue(CFSTR("network-links"),
2494 CFSTR("com.apple.srp-mdns-proxy.preferences"),
2495 kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
2496
2497 if (plist != NULL) {
2498 if (CFGetTypeID(plist) == CFArrayGetTypeID()) {
2499 bool success = true;
2500 CFArrayApplyFunction(plist, CFRangeMake(0,CFArrayGetCount(plist)), network_link_apply, &success);
2501 if (success) {
2502 network_link_array = CFArrayCreateMutableCopy(NULL, 0, plist);
2503 if (network_link_array == NULL) {
2504 ERROR("ula_setup: no memory for network link array!");
2505 }
2506 }
2507 }
2508 CFRelease(plist);
2509 }
2510 }
2511
2512 // If we didn't get any links, make an empty array.
2513 if (network_link_array == NULL) {
2514 network_link_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2515 if (network_link_array == NULL) {
2516 ERROR("ula_setup: unable to make network_link_array.");
2517 } else {
2518 INFO("ula_setup: created empty network_link_array.");
2519 }
2520 }
2521
2522 // If we didn't already successfully fetch a stored prefix, try to store one.
2523 if (!have_stored_ula_prefix) {
2524 ula_generate();
2525 } else {
2526 // Set up the thread prefix.
2527 my_thread_prefix = ula_prefix;
2528 have_thread_prefix = true;
2529 }
2530 }
2531
2532 static void
2533 get_network_signature(interface_t *interface)
2534 {
2535 nwi_state_t network_state;
2536 nwi_ifstate_t interface_state;
2537 int length = 0;
2538 const uint8_t *signature = NULL;
2539 network_link_t *link = NULL;
2540 char hexbuf[60];
2541
2542 network_state = nwi_state_copy();
2543 if (network_state != NULL) {
2544 interface_state = nwi_state_get_ifstate(network_state, interface->name);
2545 if (interface_state != NULL) {
2546 signature = nwi_ifstate_get_signature(interface_state, AF_INET, &length);
2547 if (signature != NULL) {
2548 dump_network_signature(hexbuf, sizeof(hexbuf), signature, length);
2549 INFO("get_network_signature: interface " PUB_S_SRP " has ipv4 signature " PRI_S_SRP,
2550 interface->name, hexbuf);
2551 } else {
2552 signature = nwi_ifstate_get_signature(interface_state, AF_INET6, &length);
2553 if (signature != NULL) {
2554 dump_network_signature(hexbuf, sizeof(hexbuf), signature, length);
2555 INFO("get_network_signature: interface " PUB_S_SRP " has ipv6 signature " PRI_S_SRP,
2556 interface->name, hexbuf);
2557 } else {
2558 INFO("get_network_signature: no signature on " PUB_S_SRP, interface->name);
2559 }
2560 }
2561 }
2562 if (signature == NULL) {
2563 length = 0;
2564 }
2565 for (link = network_links; link != NULL; link = link->next) {
2566 if (link->signature_length == length && (length == 0 || !memcmp(link->signature, signature, length))) {
2567 break;
2568 }
2569 }
2570 if (link == NULL) {
2571 link = network_link_create(signature, length);
2572 }
2573 nwi_state_release(network_state);
2574 } else {
2575 ERROR("get_network_signature: nwi_state_copy() failed on " PUB_S_SRP, interface->name);
2576 }
2577
2578 // If we didn't get a network signature, we're going to treat that as a signature. The previous call to
2579 // network_link_create() can have the same effect.
2580 if (link == NULL) {
2581 link = network_link_create(NULL, 0);
2582 }
2583
2584 if (link != NULL && link->prefix_number == 0) {
2585 // Assign a prefix number to the link.
2586 link->prefix_number = ula_serial++;
2587 link->last_seen = ioloop_timenow();
2588
2589 // Save this link in memory.
2590 link->next = network_links;
2591 network_links = link;
2592
2593 // Save this link signature in the preferences.
2594 network_link_record(link);
2595 }
2596 if (interface->link != link) {
2597 #if defined(USE_IPCONFIGURATION_SERVICE)
2598 if (interface->on_link_prefix_configured) {
2599 interface_prefix_deconfigure(interface);
2600 }
2601 #endif
2602 interface->link = link;
2603 }
2604 }
2605
2606 bool
2607 start_icmp_listener(void)
2608 {
2609 int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
2610 int true_flag = 1;
2611 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
2612 int false_flag = 0;
2613 #endif
2614 struct icmp6_filter filter;
2615 ssize_t rv;
2616
2617 if (sock < 0) {
2618 ERROR("Unable to listen for icmp messages: " PUB_S_SRP, strerror(errno));
2619 close(sock);
2620 return false;
2621 }
2622
2623 // Only accept router advertisements and router solicits.
2624 ICMP6_FILTER_SETBLOCKALL(&filter);
2625 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
2626 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
2627 rv = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter));
2628 if (rv < 0) {
2629 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP ".", strerror(errno));
2630 close(sock);
2631 return false;
2632 }
2633
2634 // We want a source address and interface index
2635 rv = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &true_flag, sizeof(true_flag));
2636 if (rv < 0) {
2637 ERROR("Can't set IPV6_RECVPKTINFO: " PUB_S_SRP ".", strerror(errno));
2638 close(sock);
2639 return false;
2640 }
2641
2642 // We need to be able to reject RAs arriving from off-link.
2643 rv = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &true_flag, sizeof(true_flag));
2644 if (rv < 0) {
2645 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP ".", strerror(errno));
2646 close(sock);
2647 return false;
2648 }
2649
2650 #ifdef CONFIGURE_STATIC_INTERFACE_ADDRESSES
2651 // Prevent our router advertisements from updating our routing table.
2652 rv = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &false_flag, sizeof(false_flag));
2653 if (rv < 0) {
2654 ERROR("Can't set IPV6_RECVHOPLIMIT: " PUB_S_SRP ".", strerror(errno));
2655 close(sock);
2656 return false;
2657 }
2658 #endif
2659
2660 icmp_listener.io_state = ioloop_file_descriptor_create(sock, NULL, NULL);
2661 if (icmp_listener.io_state == NULL) {
2662 ERROR("No memory for ICMP I/O structure.");
2663 close(sock);
2664 return false;
2665 }
2666
2667 // Beacon out a router advertisement every three minutes.
2668 icmp_listener.unsolicited_interval = 180 * 1000;
2669 ioloop_add_reader(icmp_listener.io_state, icmp_callback);
2670
2671 // At this point we need to have a ULA prefix.
2672 ula_setup();
2673
2674 return true;
2675 }
2676
2677 static void
2678 interface_router_solicit_finalize(void *context)
2679 {
2680 interface_t *interface = context;
2681 interface->router_solicit_wakeup = NULL;
2682 }
2683
2684 static void
2685 router_solicit_callback(void *context)
2686 {
2687 interface_t *interface = context;
2688 if (interface->is_thread) {
2689 INFO("discontinuing router solicitations on thread interface " PUB_S_SRP, interface->name);
2690 return;
2691 }
2692 if (interface->num_solicits_sent >= 3) {
2693 INFO("Done sending router solicitations on " PUB_S_SRP ".", interface->name);
2694 return;
2695 }
2696 INFO("sending router solicitation on " PUB_S_SRP , interface->name);
2697 router_solicit_send(interface);
2698
2699 interface->num_solicits_sent++;
2700 ioloop_add_wake_event(interface->router_solicit_wakeup,
2701 interface, router_solicit_callback, interface_router_solicit_finalize,
2702 RTR_SOLICITATION_INTERVAL * 1000 + srp_random16() % 1024);
2703 }
2704
2705 static void
2706 start_router_solicit(interface_t *interface)
2707 {
2708 if (interface->router_solicit_wakeup == NULL) {
2709 interface->router_solicit_wakeup = ioloop_wakeup_create();
2710 if (interface->router_solicit_wakeup == 0) {
2711 ERROR("No memory for router solicit wakeup on " PUB_S_SRP ".", interface->name);
2712 return;
2713 }
2714 } else {
2715 ioloop_cancel_wake_event(interface->router_solicit_wakeup);
2716 }
2717 interface->num_solicits_sent = 0;
2718 ioloop_add_wake_event(interface->router_solicit_wakeup, interface, router_solicit_callback,
2719 interface_router_solicit_finalize, 128 + srp_random16() % 896);
2720 }
2721
2722 static void
2723 icmp_interface_subscribe(interface_t *interface, bool added)
2724 {
2725 struct ipv6_mreq req;
2726 int rv;
2727
2728 if (icmp_listener.io_state == NULL) {
2729 ERROR("Interface subscribe without ICMP listener.");
2730 return;
2731 }
2732
2733 memset(&req, 0, sizeof req);
2734 if (interface->index == -1) {
2735 ERROR("icmp_interface_subscribe called before interface index fetch for " PUB_S_SRP, interface->name);
2736 return;
2737 }
2738
2739 req.ipv6mr_multiaddr = in6addr_linklocal_allrouters;
2740 req.ipv6mr_interface = interface->index;
2741 rv = setsockopt(icmp_listener.io_state->fd, IPPROTO_IPV6, added ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, &req,
2742 sizeof req);
2743 if (rv < 0) {
2744 ERROR("Unable to " PUB_S_SRP " all-routers multicast group on " PUB_S_SRP ": " PUB_S_SRP,
2745 added ? "join" : "leave", interface->name, strerror(errno));
2746 return;
2747 } else {
2748 INFO("icmp_interface_subscribe: " PUB_S_SRP "subscribed on interface " PUB_S_SRP, added ? "" : "un",
2749 interface->name);
2750 }
2751 }
2752
2753 static interface_t *
2754 find_interface(const char *name, int ifindex)
2755 {
2756 interface_t **p_interface, *interface = NULL;
2757
2758 for (p_interface = &interfaces; *p_interface; p_interface = &(*p_interface)->next) {
2759 interface = *p_interface;
2760 if (!strcmp(name, interface->name)) {
2761 if (ifindex != -1 && interface->index != ifindex) {
2762 INFO("interface name " PUB_S_SRP " index changed from %d to %d", name, interface->index, ifindex);
2763 interface->index = ifindex;
2764 }
2765 break;
2766 }
2767 }
2768
2769 // If it's a new interface, make a structure.
2770 // We could do a callback, but don't have a use case
2771 if (*p_interface == NULL) {
2772 interface = interface_create(name, ifindex);
2773 *p_interface = interface;
2774 }
2775 return interface;
2776 }
2777
2778 NW_EXPORT_PROJECT NW_RETURNS_RETAINED nw_path_evaluator_t
2779 nw_path_create_evaluator_for_listener(nw_parameters_t parameters,
2780 int *out_error);
2781
2782 static void
2783 interface_shutdown(interface_t *interface)
2784 {
2785 icmp_message_t *router, *next;
2786 INFO("Interface " PUB_S_SRP " went away.", interface->name);
2787 if (interface->beacon_wakeup != NULL) {
2788 ioloop_cancel_wake_event(interface->beacon_wakeup);
2789 }
2790 if (interface->post_solicit_wakeup != NULL) {
2791 ioloop_cancel_wake_event(interface->post_solicit_wakeup);
2792 }
2793 if (interface->router_solicit_wakeup != NULL) {
2794 ioloop_cancel_wake_event(interface->router_solicit_wakeup);
2795 }
2796 if (interface->deconfigure_wakeup != NULL) {
2797 ioloop_cancel_wake_event(interface->deconfigure_wakeup);
2798 }
2799 if (interface->vicarious_discovery_complete != NULL) {
2800 ioloop_cancel_wake_event(interface->vicarious_discovery_complete);
2801 }
2802 for (router = interface->routers; router; router = next) {
2803 next = router->next;
2804 icmp_message_free(router);
2805 }
2806 interface->routers = NULL;
2807 if (interface->ip_configuration_service != NULL) {
2808 CFRelease(interface->ip_configuration_service);
2809 interface->ip_configuration_service = NULL;
2810 }
2811 interface->last_beacon = interface->next_beacon = 0;
2812 interface->deprecate_deadline = 0;
2813 interface->preferred_lifetime = interface->valid_lifetime = 0;
2814 interface->num_solicits_sent = 0;
2815 interface->inactive = true;
2816 interface->ineligible = true;
2817 interface->advertise_ipv6_prefix = false;
2818 interface->have_link_layer_address = false;
2819 interface->on_link_prefix_configured = false;
2820 interface->sent_first_beacon = false;
2821 interface->num_beacons_sent = 0;
2822 interface->router_discovery_complete = false;
2823 interface->router_discovery_in_progress = false;
2824 interface->vicarious_router_discovery_in_progress = false;
2825 interface->need_reconfigure_prefix = false;
2826 interface->link = NULL;
2827 }
2828
2829 static void
2830 interface_prefix_evaluate(interface_t *interface)
2831 {
2832 char hexbuf[60];
2833
2834 // We are assuming here that the network signature can't change without us seeing a state transition.
2835 // Cases where this assumption could be violated include unplugging a WiFi base station configured as
2836 // a bridge from one ethernet network and plugging it into a different one. We could trigger a
2837 // re-evaluation when an IPv4 address on an interface changes, and also when there had been a prefix
2838 // advertised and no longer is.
2839 get_network_signature(interface);
2840
2841 // This should only happen if we're really low on memory.
2842 if (interface->link == NULL) {
2843 INFO("interface_prefix_evaluate: newly active interface " PUB_S_SRP " has no link.", interface->name);
2844 return;
2845 } else {
2846 if (interface->link->primary != NULL &&
2847 (interface->link->primary->inactive || interface->link->primary->ineligible))
2848 {
2849 INFO("Removing primary interface " PUB_S_SRP " from link because it's inactive or ineligible.",
2850 interface->link->primary->name);
2851 interface->link->primary = NULL;
2852 }
2853
2854 if (interface->link->primary == NULL) {
2855 // Make this interface primary for the link.
2856 interface->link->primary = interface;
2857
2858 // Set up the interface prefix using the prefix number for the link.
2859 interface->ipv6_prefix = ula_prefix;
2860 interface->ipv6_prefix.s6_addr[6] = interface->link->prefix_number >> 8;
2861 interface->ipv6_prefix.s6_addr[7] = interface->link->prefix_number & 255;
2862
2863 dump_network_signature(hexbuf, sizeof(hexbuf), interface->link->signature,
2864 interface->link->signature_length);
2865 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf);
2866 INFO("Interface " PUB_S_SRP " is now primary for network " PRI_S_SRP " with prefix "
2867 PRI_SEGMENTED_IPv6_ADDR_SRP, interface->name, hexbuf,
2868 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf));
2869 } else {
2870 if (interface->link->primary != interface) {
2871 INFO("interface_prefix_evaluate: not setting up " PUB_S_SRP " because interface " PUB_S_SRP
2872 " is primary for the link.", interface->name, interface->link->primary->name);
2873 }
2874 }
2875 }
2876 }
2877
2878 static void
2879 interface_active_state_evaluate(interface_t *interface, bool active_known, bool active)
2880 {
2881 INFO("interface_active_state_evaluate: evaluating interface active status - ifname: " PUB_S_SRP
2882 ", active_known: " PUB_S_SRP ", active: " PUB_S_SRP ", inactive: " PUB_S_SRP,
2883 interface->name, active_known ? "true" : "false", active ? "true" : "false",
2884 interface->inactive ? "true" : "false");
2885
2886 if (active_known && !active) {
2887 if (!interface->inactive) {
2888 // If we are the primary interface for the link to which we were connected, see if there's
2889 // another interface on the link and in any case make this interface not primary for that
2890 // link.
2891 if (interface->link != NULL && interface->link->primary == interface) {
2892 interface_t *scan;
2893 interface->link->primary = NULL;
2894 for (scan = interfaces; scan; scan = scan->next) {
2895 if (scan != interface && scan->link == interface->link && !scan->inactive && !scan->ineligible) {
2896 // Set up the thread-local prefix
2897 interface_prefix_evaluate(scan);
2898
2899 // We need to reevaluate routing policy on the new primary interface now, because
2900 // there may be no new event there to trigger one.
2901 routing_policy_evaluate(scan, true);
2902 break;
2903 }
2904 }
2905 }
2906
2907 // Clean the slate.
2908 icmp_interface_subscribe(interface, false);
2909 interface_shutdown(interface);
2910
2911 // Zero IPv4 addresses.
2912 interface->num_ipv4_addresses = 0;
2913
2914 INFO("interface_active_state_evaluate: interface went down - ifname: " PUB_S_SRP, interface->name);
2915 }
2916 } else if (active_known) {
2917 if (interface->inactive) {
2918 INFO("interface_active_state_evaluate: interface " PUB_S_SRP " showed up.", interface->name);
2919 #ifdef RA_TESTER
2920 if (!strcmp(interface->name, thread_interface_name) || !strcmp(interface->name, home_interface_name)) {
2921 #endif
2922 // Zero IPv4 addresses.
2923 interface->num_ipv4_addresses = 0;
2924
2925 icmp_interface_subscribe(interface, true);
2926 interface->inactive = false;
2927
2928 interface_prefix_evaluate(interface);
2929 #ifndef RA_TESTER
2930 if (partition_can_provide_routing) {
2931 #endif
2932 router_discovery_start(interface);
2933
2934 // If we already have a thread prefix, trigger beaconing now.
2935 if (published_thread_prefix != NULL || adopted_thread_prefix != NULL) {
2936 interface_beacon_schedule(interface, 0);
2937 } else {
2938 INFO("No prefix on thread network, so not scheduling beacon.");
2939 }
2940 #ifndef RA_TESTER
2941 } else {
2942 INFO("Can't provide routing, so not scheduling beacon.");
2943 }
2944 #endif
2945 #ifdef RA_TESTER
2946 } else {
2947 INFO("interface_active_state_evaluate: skipping interface " PUB_S_SRP
2948 " because it's not home or thread.", interface->name);
2949 }
2950 #endif
2951 }
2952 }
2953 }
2954
2955 static void
2956 nw_interface_state_changed(nw_interface_t iface, int sock, const char *name, bool ineligible)
2957 {
2958 int ifindex = nw_interface_get_index(iface);
2959 bool active = true;
2960 bool active_known = false;
2961 interface_t *interface;
2962 struct ifmediareq media_request;
2963
2964 interface = find_interface(name, ifindex);
2965 if (interface == NULL) {
2966 return;
2967 }
2968
2969 if (ineligible) {
2970 return;
2971 }
2972 if (interface->ineligible) {
2973 INFO("nw_interface_state_changed: interface " PUB_S_SRP " is eligible to be used for routing.", name);
2974 }
2975 interface->ineligible = false;
2976
2977 INFO("nw_interface_state_changed: interface " PUB_S_SRP " index %d: " PUB_S_SRP ", " PUB_S_SRP ")",
2978 name, ifindex, (active_known ? (active ? "active" : "inactive") : "unknown"),
2979 ineligible ? "ineligible" : "eligible");
2980
2981 if (sock > 0) {
2982 memset(&media_request, 0, sizeof(media_request));
2983 strlcpy(media_request.ifm_name, name, sizeof(media_request.ifm_name));
2984 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)&media_request) >= 0) {
2985 if (media_request.ifm_status & IFM_ACTIVE) {
2986 active = true;
2987 active_known = true;
2988 } else {
2989 active = false;
2990 active_known = true;
2991 }
2992 }
2993 } else {
2994 active = false;
2995 active_known = false;
2996 }
2997
2998 if (interface->index == -1) {
2999 interface->index = ifindex;
3000 }
3001 interface_active_state_evaluate(interface, active_known, active);
3002 }
3003
3004 static void
3005 ifaddr_callback(void *__unused context, const char *name, const addr_t *address, const addr_t *mask,
3006 unsigned flags, enum interface_address_change change)
3007 {
3008 char addrbuf[INET6_ADDRSTRLEN];
3009 const uint8_t *addrbytes, *maskbytes, *prefp;
3010 int preflen, i;
3011 interface_t *interface;
3012 bool is_thread_interface = false;
3013
3014 interface = find_interface(name, -1);
3015 if (interface == NULL) {
3016 ERROR("ifaddr_callback: find_interface returned NULL for " PUB_S_SRP, name);
3017 return;
3018 }
3019
3020 if (thread_interface_name != NULL && !strcmp(name, thread_interface_name)) {
3021 is_thread_interface = true;
3022 }
3023
3024 if (address->sa.sa_family == AF_INET) {
3025 addrbytes = (uint8_t *)&address->sin.sin_addr;
3026 maskbytes = (uint8_t *)&mask->sin.sin_addr;
3027 prefp = maskbytes + 3;
3028 preflen = 32;
3029 if (change == interface_address_added) {
3030 // Just got an IPv4 address?
3031 if (!interface->num_ipv4_addresses) {
3032 interface_prefix_evaluate(interface);
3033 }
3034 interface->num_ipv4_addresses++;
3035 } else if (change == interface_address_deleted) {
3036 interface->num_ipv4_addresses--;
3037 // Just lost our last IPv4 address?
3038 if (!interface->num_ipv4_addresses) {
3039 interface_prefix_evaluate(interface);
3040 }
3041 }
3042 } else if (address->sa.sa_family == AF_INET6) {
3043 addrbytes = (uint8_t *)&address->sin6.sin6_addr;
3044 maskbytes = (uint8_t *)&mask->sin6.sin6_addr;
3045 prefp = maskbytes + 15;
3046 preflen = 128;
3047 } else if (address->sa.sa_family == AF_LINK) {
3048 snprintf(addrbuf, sizeof addrbuf, "%02x:%02x:%02x:%02x:%02x:%02x",
3049 address->ether_addr.addr[0], address->ether_addr.addr[1],
3050 address->ether_addr.addr[2], address->ether_addr.addr[3],
3051 address->ether_addr.addr[4], address->ether_addr.addr[5]);
3052 prefp = (uint8_t *)&addrbuf[0]; maskbytes = prefp + 1; // Skip prefix length calculation
3053 preflen = 0;
3054 addrbytes = NULL;
3055 } else {
3056 INFO("ifaddr_callback: Unknown address type %d", address->sa.sa_family);
3057 return;
3058 }
3059
3060 if (change != interface_address_unchanged) {
3061 if (address->sa.sa_family == AF_LINK) {
3062 if (!interface->ineligible) {
3063 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP " " PUB_S_SRP " " PRI_MAC_ADDR_SRP " flags %x",
3064 name, is_thread_interface ? " (thread)" : "",
3065 change == interface_address_added ? "added" : "removed",
3066 MAC_ADDR_PARAM_SRP(address->ether_addr.addr), flags);
3067 }
3068 } else {
3069 for (; prefp >= maskbytes; prefp--) {
3070 if (*prefp) {
3071 break;
3072 }
3073 preflen -= 8;
3074 }
3075 for (i = 0; i < 8; i++) {
3076 if (*prefp & (1<<i)) {
3077 break;
3078 }
3079 --preflen;
3080 }
3081 inet_ntop(address->sa.sa_family, addrbytes, addrbuf, sizeof addrbuf);
3082 if (!interface->ineligible) {
3083 if (address->sa.sa_family == AF_INET) {
3084 IPv4_ADDR_GEN_SRP(addrbytes, addr_buf);
3085 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP " " PUB_S_SRP " " PRI_IPv4_ADDR_SRP
3086 "/%d flags %x", name, is_thread_interface ? " (thread)" : "",
3087 change == interface_address_added ? "added" : "removed",
3088 IPv4_ADDR_PARAM_SRP(addrbytes, addr_buf), preflen, flags);
3089 } else if (address->sa.sa_family == AF_INET6) {
3090 SEGMENTED_IPv6_ADDR_GEN_SRP(addrbytes, addr_buf);
3091 INFO("ifaddr_callback: interface " PUB_S_SRP PUB_S_SRP " " PUB_S_SRP " " PRI_SEGMENTED_IPv6_ADDR_SRP
3092 "/%d flags %x", name, is_thread_interface ? " (thread)" : "",
3093 change == interface_address_added ? "added" : "removed",
3094 SEGMENTED_IPv6_ADDR_PARAM_SRP(addrbytes, addr_buf), preflen, flags);
3095 } else {
3096 INFO("ifaddr_callback - invalid sa_family: %d", address->sa.sa_family);
3097 }
3098
3099 // When new IP address is removed, it is possible that the existing router information, such as
3100 // PIO and RIO is no longer valid since srp-mdns-proxy is losing its IP address. In order to let it to
3101 // flush the stale router information as soon as possible, we mark all the router as stale immediately,
3102 // by setting the router received time to a value which is 601s ago (router will be stale if the router
3103 // information is received for more than 600s). And then do router discovery for 20s, so we can ensure
3104 // that all the stale router information will be updated during the discovery, or flushed away. If all
3105 // routers are flushed, then srp-mdns-proxy will advertise its own prefix and configure the new IPv6
3106 // address.
3107 if ((address->sa.sa_family == AF_INET || address->sa.sa_family == AF_INET6) &&
3108 change == interface_address_deleted) {
3109 INFO("ifaddr_callback: making all routers stale and start router discovery due to removed address");
3110 adjust_router_received_time(interface, ioloop_timenow(),
3111 -(MAX_ROUTER_RECEIVED_TIME_GAP_BEFORE_STALE + MSEC_PER_SEC));
3112 // Explicitly set router_discovery_complete to false so we can ensure that srp-mdns-proxy will start
3113 // the router discovery immediately.
3114 interface->router_discovery_complete = false;
3115 // Set need_reconfigure_prefix to true to let routing_policy_evaluate know that the router discovery
3116 // is caused by interface removal event, so when the router discovery finished and nothing changes,
3117 // it can reconfigure the IPv6 routing in case configured does not handle it correctly.
3118 interface->need_reconfigure_prefix = true;
3119 routing_policy_evaluate(interface, false);
3120 }
3121 }
3122 }
3123 }
3124
3125 // Not a broadcast interface
3126 if (flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) {
3127 // Not the thread interface
3128 if (!is_thread_interface) {
3129 return;
3130 }
3131 }
3132
3133 // 169.254.*
3134 if (address->sa.sa_family == AF_INET && IN_LINKLOCAL(address->sin.sin_addr.s_addr)) {
3135 return;
3136 }
3137
3138 if (interface->index == -1) {
3139 interface->index = address->ether_addr.index;
3140 }
3141 interface->is_thread = is_thread_interface;
3142
3143 #if TARGET_OS_TV && !defined(RA_TESTER)
3144 if (is_thread_interface && address->sa.sa_family == AF_INET6) {
3145 partition_utun0_address_changed(&address->sin6.sin6_addr, change);
3146 }
3147 #endif
3148
3149 if (address->sa.sa_family == AF_INET) {
3150 } else if (address->sa.sa_family == AF_INET6) {
3151 if (IN6_IS_ADDR_LINKLOCAL(&address->sin6.sin6_addr)) {
3152 interface->link_local = address->sin6.sin6_addr;
3153 }
3154 } else if (address->sa.sa_family == AF_LINK) {
3155 if (address->ether_addr.len == 6) {
3156 memcpy(interface->link_layer, address->ether_addr.addr, 6);
3157 interface->have_link_layer_address = true;
3158 }
3159 }
3160 }
3161
3162 static void
3163 refresh_interface_list(void)
3164 {
3165 ioloop_map_interface_addresses(NULL, ifaddr_callback);
3166 }
3167
3168 static void
3169 nw_path_event(nw_path_t path)
3170 {
3171 int sock = socket(PF_INET6, SOCK_DGRAM, 0);
3172 INFO("nw_path_event");
3173 nw_path_enumerate_interfaces(path, ^bool (nw_interface_t NONNULL iface) {
3174 const char *name = nw_interface_get_name(iface);
3175 CFStringRef sc_name = CFStringCreateWithCStringNoCopy(NULL, name, kCFStringEncodingUTF8, kCFAllocatorNull);
3176 if (sc_name != NULL) {
3177 SCNetworkInterfaceRef _SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator,
3178 CFStringRef bsdName, UInt32 flags);
3179 SCNetworkInterfaceRef sc_interface = _SCNetworkInterfaceCreateWithBSDName(NULL, sc_name, 0);
3180 CFRelease(sc_name);
3181 if (sc_interface == NULL) {
3182 ERROR("SCNetworkInterfaceCreateWithBSDName failed");
3183 nw_interface_state_changed(iface, sock, name, true);
3184 goto out;
3185 } else {
3186 CFStringRef sc_type = SCNetworkInterfaceGetInterfaceType(sc_interface);
3187 if (sc_type == NULL) {
3188 ERROR("Unable to get interface type on " PUB_S_SRP, name);
3189 CFRelease(sc_interface);
3190 goto out;
3191 }
3192 CFStringRef _SCNetworkInterfaceGetIOPath(SCNetworkInterfaceRef interface);
3193 CFStringRef io_path = _SCNetworkInterfaceGetIOPath(sc_interface);
3194 bool is_usb = false;
3195 if (io_path == NULL) {
3196 if (strncmp(name, "utun", 4)) {
3197 ERROR("Unable to get interface I/O path.");
3198 }
3199 } else {
3200 #ifdef DEBUG_VERBOSE
3201 char pathname[1024];
3202 CFStringGetCString(io_path, pathname, sizeof(pathname), kCFStringEncodingUTF8);
3203 INFO("Interface " PUB_S_SRP " I/O Path: " PRI_S_SRP, name, pathname);
3204 #endif
3205 CFRange match = CFStringFind(io_path, CFSTR("AppleUSBDeviceNCMData"), 0);
3206 if (match.location != kCFNotFound) {
3207 is_usb = true;
3208 }
3209 }
3210 if (CFEqual(sc_type, kSCNetworkInterfaceTypeIEEE80211) ||
3211 (CFEqual(sc_type, kSCNetworkInterfaceTypeEthernet) && !is_usb))
3212 {
3213 nw_interface_state_changed(iface, sock, name, false);
3214 } else {
3215 nw_interface_state_changed(iface, sock, name, true);
3216 }
3217 CFRelease(sc_interface);
3218 out:
3219 ;
3220 }
3221 } else {
3222 nw_interface_state_changed(iface, sock, name, true);
3223 }
3224 return true;
3225 });
3226 close(sock);
3227
3228 #if TARGET_OS_TV && !defined(RA_TESTER)
3229 // If we do not have an active interface, we can't be advertising SRP service.
3230 interface_t *interface;
3231 bool active = false;
3232 for (interface = interfaces; interface; interface = interface->next) {
3233 if (!interface->ineligible && !interface->inactive) {
3234 active = true;
3235 }
3236 }
3237 if (active && !have_non_thread_interface) {
3238 INFO("nw_path_event: we have an active interface");
3239 have_non_thread_interface = true;
3240 partition_can_advertise_service = true;
3241 } else if (!active && have_non_thread_interface) {
3242 INFO("nw_path_event: we no longer have an active interface");
3243 have_non_thread_interface = false;
3244 // Stop advertising the service, if we are doing so.
3245 partition_discontinue_srp_service();
3246 }
3247 #endif // TARGET_OS_TV && !defined(RA_TESTER)
3248
3249 refresh_interface_list();
3250 }
3251
3252 #if TARGET_OS_TV && !defined(RA_TESTER)
3253 #ifdef GET_TUNNEL_NAME_WITH_WPANCTL
3254 static void
3255 thread_interface_output(io_t *io, void *__unused context)
3256 {
3257 char inbuf[512];
3258 ssize_t rv;
3259 char *s, *t;
3260
3261 // We are assuming that wpanctl will never do partial-line writes.
3262 rv = read(io->fd, inbuf, sizeof(inbuf) - 1);
3263 if (rv < 0) {
3264 ERROR("thread_interface_output: " PUB_S_SRP, strerror(errno));
3265 }
3266 INFO("read %" PRIs64 " bytes from wpanctl output", rv);
3267 if (rv <= 0) {
3268 INFO("Done with thread interface output.");
3269 ioloop_close(io);
3270 } else {
3271 if (inbuf[rv - 1] == '\n') {
3272 inbuf[rv - 1] = 0;
3273 s = strchr(inbuf, '>');
3274 if (s == NULL) {
3275 bad:
3276 ERROR("Bad wpanctl output: " PUB_S_SRP, inbuf);
3277 return;
3278 }
3279 s = strchr(s, '(');
3280 if (s == NULL) {
3281 goto bad;
3282 }
3283 // We don't expect the end of string here.
3284 if (*++s == '\0') {
3285 goto bad;
3286 }
3287 t = strchr(s, ')');
3288 if (s == t || t == NULL) {
3289 goto bad;
3290 }
3291 *t = '\0';
3292 if (num_thread_interfaces != 0) {
3293 INFO("Already have a thread interface.");
3294 } else {
3295 num_thread_interfaces = 1;
3296 thread_interface_name = strdup(s);
3297 if (thread_interface_name == NULL) {
3298 ERROR("No memory to save thread interface name " PUB_S_SRP, s);
3299 return;
3300 }
3301 INFO("Thread interface at " PUB_S_SRP, thread_interface_name);
3302 partition_got_tunnel_name();
3303 }
3304 } else {
3305 goto bad;
3306 }
3307 }
3308 }
3309
3310 static void
3311 thread_interface_done(void *__unused context, int status, const char *error)
3312 {
3313 if (error != NULL) {
3314 ERROR("thread_interface_done: " PUB_S_SRP, error);
3315 } else {
3316 INFO("thread_interface_done: %d.", status);
3317 }
3318 ioloop_subproc_release(thread_interface_enumerator_process);
3319 }
3320 #endif // GET_TUNNEL_NAME_WITH_WPANCTL
3321
3322 static void
3323 cti_get_tunnel_name_callback(void *__unused context, const char *name, cti_status_t status)
3324 {
3325 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
3326 INFO("cti_get_tunnel_name_callback: disconnected");
3327 adv_xpc_disconnect();
3328 return;
3329 }
3330
3331 INFO("cti_get_tunnel_name_callback: " PUB_S_SRP " %d", name != NULL ? name : "<null>", status);
3332 if (status != kCTIStatus_NoError) {
3333 return;
3334 }
3335 num_thread_interfaces = 1;
3336 if (thread_interface_name != NULL) {
3337 free(thread_interface_name);
3338 }
3339 thread_interface_name = strdup(name);
3340 if (thread_interface_name == NULL) {
3341 ERROR("No memory to save thread interface name " PUB_S_SRP, name);
3342 return;
3343 }
3344 INFO("Thread interface at " PUB_S_SRP, thread_interface_name);
3345 partition_got_tunnel_name();
3346 }
3347
3348 static void
3349 cti_get_role_callback(void *__unused context, cti_network_node_type_t role, cti_status_t status)
3350 {
3351 bool am_thread_router = false;
3352
3353 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
3354 INFO("cti_get_role_callback: disconnected");
3355 adv_xpc_disconnect();
3356 return;
3357 }
3358
3359 partition_last_role_change = ioloop_timenow();
3360
3361 if (status == kCTIStatus_NoError) {
3362 if (role == kCTI_NetworkNodeType_Router || role == kCTI_NetworkNodeType_Leader) {
3363 am_thread_router = true;
3364 }
3365
3366 INFO("role is: " PUB_S_SRP " (%d)\n ", am_thread_router ? "router" : "not router", role);
3367 } else {
3368 ERROR("cti_get_role_callback: nonzero status %d", status);
3369 }
3370
3371 // Our thread role doesn't actually matter, but it's useful to report it in the logs.
3372 }
3373
3374 static void
3375 cti_get_state_callback(void *__unused context, cti_network_state_t state, cti_status_t status)
3376 {
3377 bool associated = false;
3378
3379 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
3380 INFO("cti_get_state_callback: disconnected");
3381 adv_xpc_disconnect();
3382 return;
3383 }
3384
3385 partition_last_state_change = ioloop_timenow();
3386
3387 if (status == kCTIStatus_NoError) {
3388 if ((state == kCTI_NCPState_Associated) || (state == kCTI_NCPState_Isolated) ||
3389 (state == kCTI_NCPState_NetWake_Asleep) || (state == kCTI_NCPState_NetWake_Waking))
3390 {
3391 associated = true;
3392 }
3393
3394 INFO("state is: " PUB_S_SRP " (%d)\n ", associated ? "associated" : "not associated", state);
3395 } else {
3396 ERROR("cti_get_state_callback: nonzero status %d", status);
3397 }
3398
3399 if (current_thread_state != state) {
3400 if (associated) {
3401 current_thread_state = state;
3402 partition_maybe_enable_services(); // but probably not
3403 } else {
3404 current_thread_state = state;
3405 partition_disable_service();
3406 }
3407 }
3408 }
3409
3410 static void
3411 cti_get_partition_id_callback(void *__unused context, int32_t partition_id, cti_status_t status)
3412 {
3413 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
3414 INFO("cti_get_partition_id_callback: disconnected");
3415 adv_xpc_disconnect();
3416 return;
3417 }
3418
3419 if (status == kCTIStatus_NoError) {
3420 INFO("Partition ID changed to %" PRIu32, partition_id);
3421 thread_partition_id[0] = (uint8_t)((partition_id >> 24) & 255);
3422 thread_partition_id[1] = (uint8_t)((partition_id >> 16) & 255);
3423 thread_partition_id[2] = (uint8_t)((partition_id >> 8) & 255);
3424 thread_partition_id[3] = (uint8_t)(partition_id & 255);
3425
3426 partition_id_changed();
3427 } else {
3428 ERROR("cti_get_state_callback: nonzero status %d", status);
3429 }
3430 }
3431
3432 static void
3433 thread_service_note(thread_service_t *service, const char *event_description)
3434 {
3435 uint16_t port;
3436
3437 port = (service->port[0] << 8) | service->port[1];
3438 SEGMENTED_IPv6_ADDR_GEN_SRP(service->address, service_add_buf);
3439 INFO("SRP service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d " PUB_S_SRP,
3440 SEGMENTED_IPv6_ADDR_PARAM_SRP(service->address, service_add_buf),
3441 port, event_description);
3442 }
3443
3444 static void
3445 thread_pref_id_note(thread_pref_id_t *pref_id, const char *event_description)
3446 {
3447 struct in6_addr addr;
3448
3449 addr.s6_addr[0] = 0xfd;
3450 memcpy(&addr.s6_addr[1], pref_id->prefix, 5);
3451 memset(&addr.s6_addr[6], 0, 10);
3452 SEGMENTED_IPv6_ADDR_GEN_SRP(addr.s6_addr, addr_buf);
3453 INFO("pref:id " PRI_SEGMENTED_IPv6_ADDR_SRP ":%02x%02x%02x%02x " PUB_S_SRP,
3454 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr.s6_addr, addr_buf),
3455 pref_id->partition_id[0], pref_id->partition_id[1], pref_id->partition_id[2], pref_id->partition_id[3],
3456 event_description);
3457 }
3458
3459 typedef struct state_debug_accumulator {
3460 char change[20]; // " +stable +user +ncp"
3461 char *p_change;
3462 size_t left;
3463 bool changed;
3464 } accumulator_t;
3465
3466 static void
3467 accumulator_init(accumulator_t *accumulator)
3468 {
3469 memset(accumulator, 0, sizeof(*accumulator));
3470 accumulator->p_change = accumulator->change;
3471 accumulator->left = sizeof(accumulator->change);
3472 }
3473
3474 static void
3475 accumulate(accumulator_t *accumulator, bool previous, bool cur, const char *name)
3476 {
3477 size_t len;
3478 if (previous != cur) {
3479 snprintf(accumulator->p_change, accumulator->left, "%s%s%s",
3480 accumulator->p_change == accumulator->change ? "" : " ", cur ? "+" : "-", name);
3481 len = strlen(accumulator->p_change);
3482 accumulator->p_change += len;
3483 accumulator->left -= len;
3484 accumulator->changed = true;
3485 }
3486 }
3487
3488 static void
3489 cti_service_list_callback(void *__unused context, cti_service_vec_t *services, cti_status_t status)
3490 {
3491 size_t i;
3492 thread_service_t **pservice = &thread_services, *service = NULL;
3493 thread_pref_id_t **ppref_id = &thread_pref_ids, *pref_id = NULL;
3494
3495 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
3496 INFO("cti_get_service_list_callback: disconnected");
3497 adv_xpc_disconnect();
3498 return;
3499 }
3500
3501 if (status != kCTIStatus_NoError) {
3502 ERROR("cti_get_service_list_callback: %d", status);
3503 } else {
3504 // Delete any SRP services that are not in the list provided by Thread.
3505 while (*pservice != NULL) {
3506 service = *pservice;
3507 for (i = 0; i < services->num; i++) {
3508 cti_service_t *cti_service = services->services[i];
3509 // Is this a valid SRP service?
3510 if (IS_SRP_SERVICE(cti_service)) {
3511 // Is this service still present?
3512 if (!memcmp(&service->address, cti_service->server, 16) &&
3513 !memcmp(&service->port, &cti_service->server[16], 2)) {
3514 break;
3515 }
3516 }
3517 }
3518 if (i == services->num) {
3519 thread_service_note(service, "went away");
3520 *pservice = service->next;
3521 RELEASE_HERE(service, thread_service_finalize);
3522 } else {
3523 // We'll re-initialize these flags from the service list when we check for duplicates.
3524 service->previous_user = service->user;
3525 service->user = false;
3526 service->previous_stable = service->stable;
3527 service->stable = false;
3528 service->previous_ncp = service->ncp;
3529 service->ncp = false;
3530 pservice = &service->next;
3531 }
3532 }
3533 // On exit, pservice is pointing to the end-of-list pointer.
3534
3535 // Delete any pref_id services that are not in the list provided by Thread.
3536 while (*ppref_id != NULL) {
3537 pref_id = *ppref_id;
3538 for (i = 0; i < services->num; i++) {
3539 cti_service_t *cti_service = services->services[i];
3540 // Is this an SRP service?
3541 if (IS_PREF_ID_SERVICE(cti_service)) {
3542 // Is this service still present?
3543 if (!memcmp(&pref_id->partition_id, cti_service->server, 4) &&
3544 !memcmp(pref_id->prefix, &cti_service->server[4], 5))
3545 {
3546 break;
3547 }
3548 }
3549 }
3550 if (i == services->num) {
3551 thread_pref_id_note(pref_id, "went away");
3552 *ppref_id = pref_id->next;
3553 RELEASE_HERE(pref_id, thread_pref_id_finalize);
3554 } else {
3555 // We'll re-initialize these flags from the service list when we check for duplicates.
3556 pref_id->previous_user = pref_id->user;
3557 pref_id->user = false;
3558 pref_id->previous_stable = pref_id->stable;
3559 pref_id->stable = false;
3560 pref_id->previous_ncp = pref_id->ncp;
3561 pref_id->ncp = false;
3562 ppref_id = &pref_id->next;
3563 }
3564 }
3565 // On exit, pservice is pointing to the end-of-list pointer.
3566
3567 // Add any services that are not present.
3568 for (i = 0; i < services->num; i++) {
3569 cti_service_t *cti_service = services->services[i];
3570 if (IS_SRP_SERVICE(cti_service)) {
3571 for (service = thread_services; service != NULL; service = service->next) {
3572 if (!memcmp(&service->address, cti_service->server, 16) &&
3573 !memcmp(&service->port, &cti_service->server[16], 2)) {
3574 break;
3575 }
3576 }
3577 if (service == NULL) {
3578 service = thread_service_create(cti_service->server, &cti_service->server[16]);
3579 if (service == NULL) {
3580 ERROR("cti_service_list_callback: no memory for service.");
3581 } else {
3582 thread_service_note(service, "showed up");
3583 *pservice = service;
3584 pservice = &service->next;
3585 }
3586 }
3587 // Also, since we're combing the list, update ncp, user and stable flags. Note that a service can
3588 // appear more than once in the thread service list.
3589 if (service != NULL) {
3590 if (cti_service->flags & kCTIFlag_NCP) {
3591 service->ncp = true;
3592 } else {
3593 service->user = true;
3594 }
3595 if (cti_service->flags & kCTIFlag_Stable) {
3596 service->stable = true;
3597 }
3598 }
3599 } else if (IS_PREF_ID_SERVICE(cti_service)) {
3600 for (pref_id = thread_pref_ids; pref_id != NULL; pref_id = pref_id->next) {
3601 if (!memcmp(&pref_id->partition_id, cti_service->server, 4) &&
3602 !memcmp(pref_id->prefix, &cti_service->server[4], 5))
3603 {
3604 break;
3605 }
3606 }
3607 if (pref_id == NULL) {
3608 pref_id = thread_pref_id_create(cti_service->server, &cti_service->server[4]);
3609 if (pref_id == NULL) {
3610 ERROR("cti_service_list_callback: no memory for pref_id.");
3611 } else {
3612 thread_pref_id_note(pref_id, "showed up");
3613 *ppref_id = pref_id;
3614 ppref_id = &pref_id->next;
3615 }
3616 }
3617 // Also, since we're combing the list, update ncp, user and stable flags. Note that a pref_id can
3618 // appear more than once in the thread pref_id list.
3619 if (pref_id != NULL) {
3620 if (!pref_id->ncp && (cti_service->flags & kCTIFlag_NCP)) {
3621 pref_id->ncp = true;
3622 } else if (!pref_id->user && !(cti_service->flags & kCTIFlag_NCP)) {
3623 pref_id->user = true;
3624 }
3625 if (cti_service->flags & kCTIFlag_Stable) {
3626 pref_id->stable = true;
3627 }
3628 }
3629 }
3630 }
3631
3632 accumulator_t accumulator;
3633 for (service = thread_services; service != NULL; service = service->next) {
3634 accumulator_init(&accumulator);
3635 accumulate(&accumulator, service->previous_ncp, service->ncp, "ncp");
3636 accumulate(&accumulator, service->previous_stable, service->ncp, "stable");
3637 accumulate(&accumulator, service->previous_user, service->user, "user");
3638 if (accumulator.changed) {
3639 thread_service_note(service, accumulator.change);
3640 }
3641 }
3642 for (pref_id = thread_pref_ids; pref_id != NULL; pref_id = pref_id->next) {
3643 accumulator_init(&accumulator);
3644 accumulate(&accumulator, pref_id->previous_ncp, pref_id->ncp, "ncp");
3645 accumulate(&accumulator, pref_id->previous_stable, pref_id->ncp, "stable");
3646 accumulate(&accumulator, pref_id->previous_user, pref_id->user, "user");
3647 if (accumulator.changed) {
3648 thread_pref_id_note(pref_id, accumulator.change);
3649 }
3650 }
3651
3652 // At this point the thread prefix list contains the same information as what we just received.
3653 // Trigger a "prefix set changed" event.
3654 partition_service_set_changed();
3655 }
3656 }
3657
3658 static void
3659 cti_prefix_list_callback(void *__unused context, cti_prefix_vec_t *prefixes, cti_status_t status)
3660 {
3661 size_t i;
3662 thread_prefix_t **ppref = &thread_prefixes, *prefix = NULL;
3663
3664 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
3665 INFO("cti_get_prefix_list_callback: disconnected");
3666 adv_xpc_disconnect();
3667 return;
3668 }
3669
3670 if (status != kCTIStatus_NoError) {
3671 ERROR("cti_get_prefix_list_callback: %d", status);
3672 } else {
3673 // Delete any prefixes that are not in the list provided by Thread.
3674 while (*ppref != NULL) {
3675 prefix = *ppref;
3676 for (i = 0; i < prefixes->num; i++) {
3677 cti_prefix_t *cti_prefix = prefixes->prefixes[i];
3678 // Is this prefix still present?
3679 if (!memcmp(&prefix->prefix, &cti_prefix->prefix, 8)) {
3680 break;
3681 }
3682 }
3683 if (i == prefixes->num) {
3684 *ppref = prefix->next;
3685 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
3686 INFO("cti_prefix_list_callback: prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " went away",
3687 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf));
3688 RELEASE_HERE(prefix, thread_prefix_finalize);
3689 } else {
3690 // We'll re-initialize these flags from the prefix list when we check for duplicates.
3691 prefix->user = false;
3692 prefix->stable = false;
3693 prefix->ncp = false;
3694 ppref = &prefix->next;
3695 }
3696 }
3697 // On exit, ppref is pointing to the end-of-list pointer.
3698
3699 // Add any prefixes that are not present.
3700 for (i = 0; i < prefixes->num; i++) {
3701 cti_prefix_t *cti_prefix = prefixes->prefixes[i];
3702 for (prefix = thread_prefixes; prefix != NULL; prefix = prefix->next) {
3703 if (!memcmp(&prefix->prefix, &cti_prefix->prefix, 16)) {
3704 break;
3705 }
3706 }
3707 if (prefix == NULL) {
3708 prefix = thread_prefix_create(&cti_prefix->prefix, cti_prefix->prefix_length);
3709 if (prefix == NULL) {
3710 ERROR("cti_prefix_list_callback: no memory for prefix.");
3711 } else {
3712 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
3713 INFO("cti_prefix_list_callback: prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " showed up",
3714 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf));
3715 *ppref = prefix;
3716 ppref = &prefix->next;
3717 }
3718 }
3719 // Also, since we're combing the list, update ncp, user and stable flags. Note that a prefix can
3720 // appear more than once in the thread prefix list.
3721 if (prefix != NULL) {
3722 if (cti_prefix->flags & kCTIFlag_NCP) {
3723 prefix->ncp = true;
3724 } else {
3725 prefix->user = true;
3726 }
3727 if (cti_prefix->flags & kCTIFlag_Stable) {
3728 prefix->stable = true;
3729 }
3730 }
3731 }
3732
3733 // At this point the thread prefix list contains the same information as what we just received.
3734 // Trigger a "prefix set changed" event.
3735 partition_prefix_set_changed();
3736 }
3737 }
3738
3739 static void
3740 get_thread_interface_list(void)
3741 {
3742 #ifdef GET_TUNNEL_NAME_WITH_WPANCTL
3743 char *args[] = { "list" };
3744 INFO("/usr/local/bin/wpanctl list");
3745 thread_interface_enumerator_process = ioloop_subproc("/usr/local/bin/wpanctl", args, 1,
3746 thread_interface_done,
3747 thread_interface_output, NULL);
3748 if (thread_interface_enumerator_process == NULL) {
3749 ERROR("Unable to enumerate thread interfaces.");
3750 }
3751 #endif
3752
3753 }
3754 #endif // TARGET_OS_TV && !RA_TESTER
3755
3756 #ifdef TCPDUMP_LOGGER
3757 static void
3758 tcpdump_output(io_t *io, void *__unused context)
3759 {
3760 static char inbuf[1024];
3761 static int offset;
3762 ssize_t rv;
3763 char *s;
3764
3765 if (offset + 1 != sizeof(inbuf)) {
3766 rv = read(io->fd, &inbuf[offset], sizeof(inbuf) - 1 - offset);
3767 if (rv < 0) {
3768 ERROR("tcpdump_output: " PUB_S_SRP, strerror(errno));
3769 return;
3770 }
3771 if (rv <= 0) {
3772 INFO("Done with thread interface output.");
3773 ioloop_close(io);
3774 return;
3775 }
3776 offset += rv;
3777 }
3778 inbuf[offset] = 0;
3779 if (offset + 1 == sizeof(inbuf)) {
3780 s = &inbuf[offset];
3781 } else {
3782 s = strchr(inbuf, '\n');
3783 if (s == NULL) {
3784 return;
3785 }
3786 *s = 0;
3787 }
3788 INFO(PUB_S_SRP, inbuf);
3789 if (s != &inbuf[offset]) {
3790 memmove(inbuf, s, &inbuf[offset] - s);
3791 }
3792 offset = 0;
3793 }
3794
3795 static void
3796 tcpdump_done(void *__unused context, int status, const char *error)
3797 {
3798 if (error != NULL) {
3799 ERROR("tcpdump_done: " PUB_S_SRP, error);
3800 } else {
3801 INFO("tcpdump_done: %d.", status);
3802 }
3803 ioloop_subproc_release(tcpdump_logger_process);
3804 }
3805
3806 static void
3807 start_tcpdump_logger(void)
3808 {
3809 char *args[] = { "-vv", "-s", "1500", "-n", "-e", "-i", "utun0", "-l", "udp", "port", "53" };
3810 INFO("/usr/sbin/tcpdump -vv -s 1500 -n -e -i utun0 udp port 53");
3811 tcpdump_logger_process = ioloop_subproc("/usr/sbin/tcpdump", args, 11, tcpdump_done,
3812 tcpdump_output, NULL);
3813 if (tcpdump_logger_process == NULL) {
3814 ERROR("Unable to start tcpdump logger.");
3815 }
3816 }
3817 #endif // TCPDUMP_LOGGER
3818
3819 void
3820 thread_network_startup(void)
3821 {
3822 INFO("thread_network_startup: Thread network started.");
3823
3824 #ifdef MONTIOR_ROUTING_SOCKET
3825 start_route_listener();
3826 #else
3827 int error = 0;
3828 nw_parameters_t params = nw_parameters_create();
3829 if (path_evaluator != NULL) {
3830 nw_path_evaluator_cancel(path_evaluator);
3831 nw_release(path_evaluator);
3832 }
3833 path_evaluator = nw_path_create_evaluator_for_listener(params, &error);
3834 nw_release(params);
3835 if (path_evaluator == NULL || error != 0) {
3836 ERROR("thread_network_startup: Unable to create network path evaluator.");
3837 return;
3838 }
3839 nw_path_evaluator_set_update_handler(path_evaluator, dispatch_get_main_queue(), ^(nw_path_t path) {
3840 nw_path_event(path);
3841 });
3842 nw_path_t initial = nw_path_evaluator_copy_path(path_evaluator);
3843 nw_path_event(initial);
3844 nw_release(initial);
3845 #endif // MONITOR_ROUTING_SOCKET
3846 #if TARGET_OS_TV && !defined(RA_TESTER)
3847 get_thread_interface_list();
3848 #endif
3849 set_thread_forwarding();
3850 #ifdef TCPDUMP_LOGGER
3851 start_tcpdump_logger();
3852 #endif
3853
3854 #ifndef RA_TESTER
3855 cti_get_state(&thread_state_context, NULL, cti_get_state_callback, dispatch_get_main_queue());
3856 cti_get_network_node_type(&thread_role_context, NULL, cti_get_role_callback, dispatch_get_main_queue());
3857 cti_get_service_list(&thread_service_context, NULL, cti_service_list_callback, dispatch_get_main_queue());
3858 cti_get_prefix_list(&thread_prefix_context, NULL, cti_prefix_list_callback, dispatch_get_main_queue());
3859 cti_get_tunnel_name(NULL, cti_get_tunnel_name_callback, dispatch_get_main_queue());
3860 cti_get_partition_id(&thread_partition_id_context, NULL, cti_get_partition_id_callback, dispatch_get_main_queue());
3861 #endif
3862 }
3863
3864 void
3865 thread_network_shutdown(void)
3866 {
3867 interface_t *interface;
3868 network_link_t *link;
3869 #ifndef RA_TESTER
3870 if (thread_state_context) {
3871 INFO("thread_network_shutdown: discontinuing state events");
3872 cti_events_discontinue(thread_state_context);
3873 }
3874 if (thread_role_context) {
3875 INFO("thread_network_shutdown: discontinuing role events");
3876 cti_events_discontinue(thread_role_context);
3877 }
3878 if (thread_service_context) {
3879 INFO("thread_network_shutdown: discontinuing service events");
3880 cti_events_discontinue(thread_service_context);
3881 }
3882 if (thread_prefix_context) {
3883 INFO("thread_network_shutdown: discontinuing prefix events");
3884 cti_events_discontinue(thread_prefix_context);
3885 }
3886 if (thread_partition_id_context) {
3887 INFO("thread_network_shutdown: discontinuing partition ID events");
3888 cti_events_discontinue(thread_partition_id_context);
3889 }
3890 #endif
3891 if (path_evaluator != NULL) {
3892 nw_path_evaluator_cancel(path_evaluator);
3893 nw_release(path_evaluator);
3894 path_evaluator = NULL;
3895 }
3896 INFO("thread_network_shutdown: Thread network shutdown.");
3897 // Stop all activity on interfaces.
3898 for (interface = interfaces; interface; interface = interface->next) {
3899 interface_shutdown(interface);
3900 }
3901 for (link = network_links; link; link = link->next) {
3902 link->primary = NULL;
3903 }
3904
3905 #ifndef RA_TESTER
3906 partition_state_reset();
3907 #endif
3908 }
3909
3910 #ifndef RA_TESTER
3911 static void
3912 partition_state_reset(void)
3913 {
3914 thread_prefix_t *prefix, *next_prefix = NULL;
3915 thread_service_t *service, *next_service = NULL;
3916 thread_pref_id_t *pref_id, *next_pref_id = NULL;
3917
3918 // Remove any saved state from the thread network.
3919 for (prefix = thread_prefixes; prefix != NULL; prefix = next_prefix) {
3920 next_prefix = prefix->next;
3921 RELEASE_HERE(prefix, thread_prefix_finalize);
3922 }
3923 thread_prefixes = NULL;
3924
3925 if (published_thread_prefix != NULL) {
3926 RELEASE_HERE(published_thread_prefix, thread_prefix_finalize);
3927 published_thread_prefix = NULL;
3928 }
3929 if (adopted_thread_prefix != NULL) {
3930 RELEASE_HERE(adopted_thread_prefix, thread_prefix_finalize);
3931 adopted_thread_prefix = NULL;
3932 }
3933
3934 for (service = thread_services; service != NULL; service = next_service) {
3935 next_service = service->next;
3936 RELEASE_HERE(service, thread_service_finalize);
3937 }
3938 thread_services = NULL;
3939
3940 for (pref_id = thread_pref_ids; pref_id != NULL; pref_id = next_pref_id) {
3941 next_pref_id = pref_id->next;
3942 RELEASE_HERE(pref_id, thread_pref_id_finalize);
3943 }
3944 thread_pref_ids = NULL;
3945
3946 current_thread_state = kCTI_NCPState_Uninitialized;
3947 current_thread_role = kCTI_NetworkNodeType_Unknown;
3948
3949 partition_last_prefix_set_change = 0;
3950 partition_last_pref_id_set_change = 0;
3951 partition_last_partition_id_change = 0;
3952 partition_last_role_change = 0;
3953 partition_last_state_change = 0;
3954 partition_settle_start = 0;
3955 partition_service_last_add_time = 0;
3956 partition_id_is_known = false;
3957 partition_have_prefix_list = false;
3958 partition_have_pref_id_list = false;
3959 partition_tunnel_name_is_known = false;
3960 partition_can_advertise_service = false;
3961 partition_can_provide_routing = false;
3962 partition_may_offer_service = false;
3963 partition_settle_satisfied = true;
3964
3965 if (partition_settle_wakeup != NULL) {
3966 ioloop_cancel_wake_event(partition_settle_wakeup);
3967 }
3968
3969 if (partition_post_partition_wakeup != NULL) {
3970 ioloop_cancel_wake_event(partition_post_partition_wakeup);
3971 }
3972
3973 if (partition_pref_id_wait_wakeup != NULL) {
3974 ioloop_cancel_wake_event(partition_pref_id_wait_wakeup);
3975 }
3976
3977 if (partition_service_add_pending_wakeup != NULL) {
3978 ioloop_cancel_wake_event(partition_service_add_pending_wakeup);
3979 }
3980 }
3981
3982 static int __unused
3983 prefcmp(uint8_t *a, uint8_t *b, int len)
3984 {
3985 int i;
3986 for (i = 0; i < len; i++) {
3987 if (a[i] < b[i]) return -1;
3988 if (a[i] > b[i]) return 1;
3989 }
3990 return 0;
3991 }
3992
3993 static void
3994 partition_prefix_remove_callback(void *__unused context, cti_status_t status)
3995 {
3996 if (status != kCTIStatus_NoError) {
3997 ERROR("partition_unpublish_my_prefix: failed to unpublish my prefix: %d.", status);
3998 } else {
3999 INFO("partition_unpublish_my_prefix: done unpublishing my prefix.");
4000 }
4001 }
4002
4003 static void
4004 partition_stop_advertising_pref_id_done(void *__unused context, cti_status_t status)
4005 {
4006 INFO("partition_stop_advertising_pref_id_done: %d", status);
4007 }
4008
4009 void
4010 partition_stop_advertising_pref_id(void)
4011 {
4012 // This should remove any copy of the service that this BR is advertising.
4013 uint8_t service_info[] = { 0, 0, 0, 1 };
4014 int status;
4015
4016 INFO("partition_stop_advertising_pref_id: %" PRIu64 "/%02x" , THREAD_ENTERPRISE_NUMBER, service_info[0]);
4017 service_info[0] = THREAD_PREF_ID_OPTION & 255;
4018 status = cti_remove_service(NULL, partition_stop_advertising_pref_id_done,
4019 dispatch_get_main_queue(),
4020 THREAD_ENTERPRISE_NUMBER, service_info, 1);
4021 if (status != kCTIStatus_NoError) {
4022 INFO("partition_stop_advertising_pref_id: status %d", status);
4023 }
4024 }
4025
4026 static void
4027 partition_advertise_pref_id_done(void *__unused context, cti_status_t status)
4028 {
4029 INFO("partition_advertise_pref_id_done: %d", status);
4030 }
4031
4032 static void
4033 partition_advertise_pref_id(uint8_t *prefix)
4034 {
4035 // This should remove any copy of the service that this BR is advertising.
4036 uint8_t service_info[] = { 0, 0, 0, 1 };
4037 uint8_t pref_id[9];
4038 memcpy(pref_id, thread_partition_id, 4);
4039 memcpy(&pref_id[4], prefix, 5);
4040 uint8_t full_prefix[6] = {0xfd, prefix[0], prefix[1], prefix[2], prefix[3], prefix[4]};
4041
4042 service_info[0] = THREAD_PREF_ID_OPTION & 255;
4043 IPv6_PREFIX_GEN_SRP(full_prefix, sizeof(full_prefix), prefix_buf);
4044 INFO("partition_advertise_pref_id: %" PRIu64 "/%02x/%02x%02x%02x%02x" PRI_IPv6_PREFIX_SRP,
4045 THREAD_ENTERPRISE_NUMBER, service_info[0], pref_id[0], pref_id[1], pref_id[2], pref_id[3],
4046 IPv6_PREFIX_PARAM_SRP(prefix_buf));
4047 int status = cti_add_service(NULL, partition_advertise_pref_id_done, dispatch_get_main_queue(),
4048 THREAD_ENTERPRISE_NUMBER, service_info, 1, pref_id, sizeof pref_id);
4049 if (status != kCTIStatus_NoError) {
4050 INFO("partition_advertise_pref_id: status %d", status);
4051 }
4052 }
4053
4054 static void
4055 partition_id_update(void)
4056 {
4057 thread_prefix_t *advertised_prefix = get_advertised_thread_prefix();
4058 if (advertised_prefix == NULL) {
4059 INFO("partition_id_update: no advertised prefix, not advertising pref:id.");
4060 } else if (advertised_prefix == adopted_thread_prefix) {
4061 INFO("partition_id_update: not advertising pref:id for adopted prefix.");
4062 partition_stop_advertising_pref_id();
4063 } else {
4064 partition_advertise_pref_id(((uint8_t *)&advertised_prefix->prefix) + 1);
4065 INFO("partition_id_update: advertised pref:id for our prefix.");
4066 }
4067 }
4068
4069 static void
4070 partition_unpublish_prefix(thread_prefix_t *prefix)
4071 {
4072 cti_status_t status = cti_remove_prefix(NULL, partition_prefix_remove_callback, dispatch_get_main_queue(),
4073 &prefix->prefix, 64);
4074 if (status != kCTIStatus_NoError) {
4075 ERROR("partition_unpublish_prefix: prefix remove failed: %d.", status);
4076 }
4077 partition_stop_advertising_pref_id();
4078 }
4079
4080 static void
4081 partition_refresh_and_re_evaluate(void)
4082 {
4083 refresh_interface_list();
4084 routing_policy_evaluate_all_interfaces(true);
4085 }
4086
4087 typedef struct unadvertised_prefix_remove_state unadvertised_prefix_remove_state_t;
4088 struct unadvertised_prefix_remove_state {
4089 int num_unadvertised_prefixes;
4090 int num_removals;
4091 void (*continuation)(void);
4092 };
4093
4094 static void
4095 partition_remove_all_prefixes_done(void *context, cti_status_t status)
4096 {
4097 unadvertised_prefix_remove_state_t *state = context;
4098 state->num_removals++;
4099 if (state->num_removals == state->num_unadvertised_prefixes) {
4100 INFO("partition_remove_all_prefixes_done: DONE: status = %d num_removals = %d num_unadvertised = %d",
4101 status, state->num_removals, state->num_unadvertised_prefixes);
4102 void (*continuation)(void) = state->continuation;
4103 free(state);
4104 if (continuation != NULL) {
4105 continuation();
4106 } else {
4107 INFO("partition_remove_all_prefixes_done: no continuation.");
4108 }
4109 } else {
4110 INFO("partition_remove_all_prefixes_done: !DONE: status = %d num_removals = %d num_unadvertised = %d",
4111 status, state->num_removals, state->num_unadvertised_prefixes);
4112 }
4113 }
4114
4115 static void
4116 partition_remove_all_unwanted_prefixes_inner(unadvertised_prefix_remove_state_t *state, thread_prefix_t *prefix)
4117 {
4118 // Don't unpublish the adopted or published prefix.
4119 if ((published_thread_prefix == NULL || memcmp(&published_thread_prefix->prefix, &prefix->prefix, 8)) &&
4120 (adopted_thread_prefix == NULL || memcmp(&adopted_thread_prefix->prefix, &prefix->prefix, 8)))
4121 {
4122 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
4123 INFO("partition_remove_all_unwanted_prefixes: Removing prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
4124 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf));
4125 cti_status_t status = cti_remove_prefix(state, partition_remove_all_prefixes_done,
4126 dispatch_get_main_queue(), &prefix->prefix, 64);
4127 if (status != kCTIStatus_NoError) {
4128 ERROR("partition_remove_all_unwanted_prefixes: prefix remove failed: %d.", status);
4129 }
4130 }
4131 }
4132
4133 static void
4134 partition_remove_all_unwanted_prefixes(void (*continuation)(void), thread_prefix_t *prefix_1, thread_prefix_t *prefix_2)
4135 {
4136 unadvertised_prefix_remove_state_t *state = calloc(1, sizeof(*state));
4137 if (state == NULL) {
4138 INFO("partition_remove_all_unwanted_prefixes: no memory");
4139 return;
4140 }
4141
4142 // It's possible for us to get into a state where a prefix is published by this BR, but doesn't
4143 // have a pref:id and isn't recognized as belonging to this BR. This should never happen in practice,
4144 // but if it does happen, the only thing that will eliminate it is a reboot. In case this happens,
4145 // we go through the list of prefixes that are marked ncp and unpublish them.
4146 thread_prefix_t *prefix;
4147
4148 state->continuation = continuation;
4149 for (prefix = thread_prefixes; prefix; prefix = prefix->next) {
4150 if (!partition_pref_id_is_present(&prefix->prefix)) {
4151 // It's possible for partition_remove_all_unwanted_prefixes to get called before we have a full list of
4152 // recently-published prefixes. It is possible for either the published prefix or the adopted prefix to
4153 // not be on the list of prefixes. The caller may however have wanted to change either of those pointers;
4154 // in this case, it will pass in either or both of those pointers as prefix_1 and prefix_2; if we see those
4155 // prefixes on the list, we don't need to unpublish them twice.
4156 if (prefix_1 != NULL && !memcmp(&prefix->prefix, &prefix_1->prefix, 8)) {
4157 prefix_1 = NULL;
4158 }
4159 if (prefix_2 != NULL && !memcmp(&prefix->prefix, &prefix_2->prefix, 8)) {
4160 prefix_2 = NULL;
4161 }
4162 state->num_unadvertised_prefixes++;
4163 }
4164 }
4165 if (prefix_1 != NULL) {
4166 state->num_unadvertised_prefixes++;
4167 }
4168 if (prefix_2 != NULL) {
4169 state->num_unadvertised_prefixes++;
4170 }
4171
4172 // Now actually remove the prefixes.
4173 for (prefix = thread_prefixes; prefix; prefix = prefix->next) {
4174 if (!partition_pref_id_is_present(&prefix->prefix)) {
4175 partition_remove_all_unwanted_prefixes_inner(state, prefix);
4176 }
4177 }
4178 if (prefix_1 != NULL) {
4179 partition_remove_all_unwanted_prefixes_inner(state, prefix_1);
4180 }
4181 if (prefix_2 != NULL) {
4182 partition_remove_all_unwanted_prefixes_inner(state, prefix_2);
4183 }
4184
4185 // If we didn't remove any prefixes, continue immediately.
4186 if (state->num_unadvertised_prefixes == 0) {
4187 if (state->continuation) {
4188 state->continuation();
4189 }
4190 free(state);
4191 } else if (!state->continuation) {
4192 free(state);
4193 #ifdef __clang_analyzer__ // clang_analyzer is unable to follow the reference through the cti code.
4194 } else {
4195 free(state);
4196 #endif
4197 }
4198 }
4199
4200 static void
4201 partition_unpublish_adopted_prefix(bool wait)
4202 {
4203 // Unpublish the adopted prefix
4204 if (adopted_thread_prefix != NULL) {
4205 partition_unpublish_prefix(adopted_thread_prefix);
4206 INFO("partition_unpublish_adopted_prefix: started to unadopt prefix.");
4207 RELEASE_HERE(adopted_thread_prefix, thread_prefix_finalize);
4208 adopted_thread_prefix = NULL;
4209 }
4210
4211 // Something changed, so do a routing policy update unless wait==true
4212 if (!wait) {
4213 partition_refresh_and_re_evaluate();
4214 }
4215 }
4216
4217 static void
4218 partition_publish_prefix_finish(void)
4219 {
4220 INFO("partition_publish_prefix_finish: prefix unpublishing has completed, time to update the prefix.");
4221
4222 partition_id_update();
4223 set_thread_prefix();
4224
4225 // Something changed, so do a routing policy update.
4226 partition_refresh_and_re_evaluate();
4227 }
4228
4229 static void
4230 partition_publish_my_prefix()
4231 {
4232 void (*continuation)(void) = NULL;
4233 thread_prefix_t *prefix_1 = NULL;
4234 thread_prefix_t *prefix_2 = NULL;
4235
4236 if (adopted_thread_prefix != NULL) {
4237 prefix_1 = adopted_thread_prefix;
4238 adopted_thread_prefix = NULL;
4239 }
4240
4241 // If we already have a published thread prefix, it really should be my_thread_prefix.
4242 if (published_thread_prefix != NULL) {
4243 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf);
4244 // This should always be false.
4245 if (memcmp(&published_thread_prefix->prefix, &my_thread_prefix, 8)) {
4246 INFO("partition_publish_my_prefix: Published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " is not my prefix",
4247 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf));
4248 prefix_2 = published_thread_prefix;
4249 published_thread_prefix = NULL;
4250 continuation = partition_publish_prefix_finish;
4251 } else {
4252 INFO("partition_publish_my_prefix: Published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " is my prefix",
4253 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf));
4254 }
4255 }
4256 if (published_thread_prefix == NULL) {
4257 // Publish the prefix
4258 published_thread_prefix = thread_prefix_create(&my_thread_prefix, 64);
4259 if (published_thread_prefix == NULL) {
4260 ERROR("partition_publish_my_prefix: No memory for locally-advertised thread prefix");
4261 goto out;
4262 }
4263 continuation = partition_publish_prefix_finish;
4264 SEGMENTED_IPv6_ADDR_GEN_SRP(my_thread_prefix.s6_addr, prefix_buf);
4265 INFO("partition_publish_my_prefix: Publishing my prefix: " PRI_SEGMENTED_IPv6_ADDR_SRP,
4266 SEGMENTED_IPv6_ADDR_PARAM_SRP(my_thread_prefix.s6_addr, prefix_buf));
4267 }
4268 partition_remove_all_unwanted_prefixes(continuation, prefix_1, prefix_2);
4269 out:
4270 if (prefix_1 != NULL) {
4271 RELEASE_HERE(prefix_1, thread_prefix_finalize);
4272 }
4273 if (prefix_2 != NULL) {
4274 RELEASE_HERE(prefix_2, thread_prefix_finalize);
4275 }
4276 }
4277
4278 static void
4279 partition_adopt_prefix(thread_prefix_t *prefix)
4280 {
4281 void (*continuation)(void) = NULL;
4282 thread_prefix_t *prefix_1 = NULL;
4283 thread_prefix_t *prefix_2 = NULL;
4284
4285 if (published_thread_prefix != NULL) {
4286 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf);
4287 INFO("partition_adopt_prefix: Removing published prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
4288 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf));
4289 prefix_1 = published_thread_prefix;
4290 published_thread_prefix = NULL;
4291 }
4292
4293 // If we already have an advertised thread prefix, it might not have changed.
4294 if (adopted_thread_prefix != NULL) {
4295 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf);
4296 if (memcmp(&adopted_thread_prefix->prefix, &prefix->prefix, 8)) {
4297 INFO("partition_adopt_prefix: Removing previously adopted prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
4298 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf));
4299 prefix_2 = adopted_thread_prefix;
4300 continuation = partition_publish_prefix_finish;
4301 } else {
4302 INFO("partition_adopt_prefix: Keeping previously adopted prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
4303 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf));
4304 }
4305 }
4306 if (adopted_thread_prefix == NULL) {
4307 // Adopt the prefix
4308 adopted_thread_prefix = prefix;
4309 RETAIN_HERE(adopted_thread_prefix);
4310 continuation = partition_publish_prefix_finish;
4311 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf);
4312 INFO("partition_adopt_prefix: Adopting prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
4313 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf));
4314 }
4315 partition_remove_all_unwanted_prefixes(continuation, prefix_1, prefix_2);
4316
4317 if (prefix_1 != NULL) {
4318 RELEASE_HERE(prefix_1, thread_prefix_finalize);
4319 }
4320 if (prefix_2 != NULL) {
4321 RELEASE_HERE(prefix_2, thread_prefix_finalize);
4322 }
4323 }
4324
4325 // Check to see if a specific prefix is still present.
4326 static bool
4327 partition_prefix_is_present(struct in6_addr *address, int length)
4328 {
4329 thread_prefix_t *prefix;
4330 // For now we assume that the comparison is as a /64.
4331 for (prefix = thread_prefixes; prefix; prefix = prefix->next) {
4332 if (prefix->prefix_len == length && !memcmp((uint8_t *)&prefix->prefix, (uint8_t *)address, 8)) {
4333 return true;
4334 }
4335 }
4336 return false;
4337 }
4338
4339 // Check to see if a valid pref:id for the specified prefix is present.
4340 static bool
4341 partition_pref_id_is_present(struct in6_addr *prefix_addr)
4342 {
4343 thread_pref_id_t *pref_id;
4344 uint8_t *prefix_bytes = (uint8_t *)prefix_addr;
4345
4346 INFO("partition_pref_id_is_present: published_thread_prefix = %p; prefix = %p", published_thread_prefix,
4347 prefix_addr);
4348
4349 // The published prefix's pref:id is always considered present.
4350 if (published_thread_prefix != NULL && !memcmp(prefix_addr, &published_thread_prefix->prefix, 8)) {
4351 INFO("partition_pref_id_is_present: prefix is published prefix");
4352 return true;
4353 }
4354
4355 for (pref_id = thread_pref_ids; pref_id; pref_id = pref_id->next) {
4356 // A pref:id is valid if the partition ID matches the current partition ID.
4357 // A pref:id matches a prefix if the 40 variable bits in the ULA /48 are the same.
4358 if (!memcmp(thread_partition_id, pref_id->partition_id, 4) &&
4359 !memcmp(prefix_bytes + 1, pref_id->prefix, 5))
4360 {
4361 INFO("partition_pref_id_is_present: pref:id is present");
4362 return true;
4363 } else {
4364 IPv6_PREFIX_GEN_SRP(pref_id->prefix, sizeof(pref_id->prefix), pref_id_prefix);
4365 if (memcmp(thread_partition_id, pref_id->partition_id, 4)) {
4366 INFO("partition_pref_id_is_present: "
4367 "pref:id for " PRI_IPv6_PREFIX_SRP
4368 ":%02x%02x%02x%02x does not match partition id %02x%02x%02x%02x",
4369 IPv6_PREFIX_PARAM_SRP(pref_id_prefix),
4370 pref_id->partition_id[0], pref_id->partition_id[1], pref_id->partition_id[2],
4371 pref_id->partition_id[3],
4372 thread_partition_id[0], thread_partition_id[1], thread_partition_id[2], thread_partition_id[3]);
4373 } else {
4374 INFO("partition_pref_id_is_present: "
4375 "pref:id for " PRI_IPv6_PREFIX_SRP ":%02x%02x%02x%02x does not match prefix %02x%02x%02x%02x%02x",
4376 IPv6_PREFIX_PARAM_SRP(pref_id_prefix),
4377 pref_id->partition_id[0], pref_id->partition_id[1], pref_id->partition_id[2],
4378 pref_id->partition_id[3],
4379 prefix_bytes[1], prefix_bytes[2], prefix_bytes[3], prefix_bytes[4], prefix_bytes[5]);
4380 }
4381 }
4382 }
4383 return false;
4384 }
4385
4386 // Find the lowest valid prefix present. The return value may be the published prefix.
4387 static thread_prefix_t *
4388 partition_find_lowest_valid_prefix(void)
4389 {
4390 thread_prefix_t *prefix, *lowest = published_thread_prefix;
4391
4392 // Are there other prefixes published?
4393 for (prefix = thread_prefixes; prefix != NULL; prefix = prefix->next) {
4394 // The prefix we publish doesn't count.
4395 if (published_thread_prefix != NULL && !memcmp(&prefix->prefix, &published_thread_prefix->prefix, 8)) {
4396 continue;
4397 }
4398 if (partition_pref_id_is_present(&prefix->prefix)) {
4399 if (lowest == NULL || memcmp(&prefix->prefix, &lowest->prefix, 8) < 0) {
4400 lowest = prefix;
4401 }
4402 break;
4403 }
4404 }
4405 return lowest;
4406 }
4407
4408 // Find the lowest valid pref:id. The return value may be the pref:id for the published prefix.
4409 static thread_pref_id_t *
4410 partition_find_lowest_valid_pref_id(void)
4411 {
4412 thread_pref_id_t *lowest = NULL;
4413 thread_pref_id_t *pref_id;
4414
4415 for (pref_id = thread_pref_ids; pref_id != NULL; pref_id = pref_id->next) {
4416 if (lowest == NULL || memcmp(pref_id->prefix, lowest->prefix, 5) < 0) {
4417 lowest = pref_id;
4418 }
4419 }
4420 return lowest;
4421 }
4422
4423 // The prefix ID timeout has gone off. At this time we evaluate the state of the network: the fact that we
4424 // got a wakeup means that there has been no partition event and nothing has changed about the set of
4425 // prefixes published on the thread mesh since the wakeup was scheduled. We don't schedule this wakeup unless
4426 // there is more than one prefix on the thread mesh. So that means that when the wakeup is called, there
4427 // is still more than one prefix+pref:id pair active on the link--an undesirable situation. So we now
4428 // hold an election. If we lose, we drop our prefix+pref:id pair in favor of the winner. If we win,
4429 // we do nothing--we are expecting the BR(s) publishing the other prefix+pref:id pair(s) to drop them.
4430 static void
4431 partition_pref_id_timeout(void *__unused context)
4432 {
4433 thread_prefix_t *prefix = partition_find_lowest_valid_prefix();
4434
4435 // This should never happen because we wouldn't have set the timeout.
4436 if (prefix == NULL) {
4437 INFO("partition_pref_id_timeout: no published prefix.");
4438 return;
4439 }
4440
4441 // If we won, do nothing.
4442 if (published_thread_prefix != NULL && (prefix == published_thread_prefix ||
4443 !memcmp(&prefix->prefix, &published_thread_prefix->prefix, 8))) {
4444 INFO("partition_pref_id_timeout: published prefix is the lowest; keeping it.");
4445 return;
4446 }
4447
4448 // published_thread_prefix should never be null here.
4449 // If our published prefix is not the lowest prefix, then we should drop it and adopt the lowest prefix.
4450 if (published_thread_prefix != NULL && memcmp(&prefix->prefix, &published_thread_prefix->prefix, 8)) {
4451 INFO("partition_pref_id_timeout: published prefix is not lowest valid prefix. Adopting lowest valid prefix.");
4452 partition_adopt_prefix(prefix);
4453 return;
4454 }
4455
4456 // We should never get here.
4457 if (adopted_thread_prefix != NULL) {
4458 if (!memcmp(&adopted_thread_prefix->prefix, &prefix->prefix, 8)) {
4459 ERROR("partition_pref_id_timeout: no published prefix. Already adopted lowest.");
4460 return;
4461 }
4462 // Unadopt this prefix since it's not lowest.
4463 partition_unpublish_adopted_prefix(false);
4464 // adopted_thread_prefix is now NULL
4465 }
4466
4467 // And we should never get here.
4468 ERROR("partition_pref_id_timeout: no published prefix. Adopting lowest.");
4469 partition_adopt_prefix(prefix);
4470 }
4471
4472 // When we see a new partition, if there isn't a prefix to adopt and we aren't publishing one,
4473 // we wait n seconds to see if some other BR publishes a prefix, but also publish our own pref:id.
4474 // If no router on the partition is publishing a prefix, then after n seconds we hold an election,
4475 // choosing the pref:id with the lowest ULA. If that's this router, then we will publish our prefix,
4476 // but if not, we want to check after a bit to make sure a prefix /does/ get published. If after
4477 // another n seconds, we still don't see a valid prefix+pref:id pair, we publish our own; if this
4478 // later turns out to have been a mistake, we will hold the election again and remove the one we
4479 // published if we don't win.
4480 static void
4481 partition_post_election_wakeup(void *__unused context)
4482 {
4483 thread_prefix_t *prefix = partition_find_lowest_valid_prefix();
4484
4485 // There is no valid prefix published. Publish ours.
4486 if (prefix == NULL) {
4487 INFO("partition_post_election_wakeup: no valid thread prefix present, publishing mine.");
4488 partition_publish_my_prefix();
4489 return;
4490 }
4491
4492 // It's perfectly valid to not have adopted the lowest prefix at this point.
4493 // However, if we have adopted a prefix, we shouldn't be here because the timeout should have been
4494 // canceled.
4495 if (adopted_thread_prefix != NULL && memcmp(&adopted_thread_prefix->prefix, &prefix->prefix, 8)) {
4496 ERROR("partition_post_election_wakeup: adopted prefix is not lowest.");
4497 } else {
4498 ERROR("partition_post_election_wakeup: adopted prefix is lowest.");
4499 }
4500 }
4501
4502 // This is the initial wakeup as described under partition_post_election_wakeup. At this time
4503 // if there is a valid published pref:id pair, we adopt it; if not, then we hold an election based
4504 // on all of the on-partition pref:id pairs that we see. If we win, we publish our prefix; otherwise
4505 // give the winner time to publish its prefix.
4506 static void
4507 partition_post_partition_timeout(void *__unused context)
4508 {
4509 thread_prefix_t *prefix = partition_find_lowest_valid_prefix();
4510 thread_pref_id_t *pref_id;
4511
4512 // Is there a prefix+pref:id published?
4513 // Actually at this point we should already have adopted it and the wakeup should have been canceled.
4514 if (prefix != NULL) {
4515 ERROR("partition_post_partition_timeout: wakeup when there's a valid lowest prefix.");
4516 return;
4517 }
4518
4519 // Are there pref:id services published that list a lower ULA than ours?
4520 pref_id = partition_find_lowest_valid_pref_id();
4521
4522 if (pref_id == NULL) {
4523 INFO("There are no prefixes published, publishing my prefix.");
4524 partition_publish_my_prefix();
4525 return;
4526 }
4527
4528 // If not, publish ours.
4529 if (memcmp(((uint8_t *)&my_thread_prefix) + 1, pref_id->prefix, 5) < 0) {
4530 INFO("partition_post_partition_timeout: my prefix id is lowest, publishing my prefix.");
4531 partition_publish_my_prefix();
4532 return;
4533 }
4534
4535 // If so, wait another ten seconds to see if one of them publishes a prefix
4536 // If we have adopted a prefix, set a timer after which we will drop it and start advertising if nothing has
4537 // happened
4538 if (partition_post_partition_wakeup != NULL) { // shouldn't be!
4539 ioloop_cancel_wake_event(partition_post_partition_wakeup);
4540 } else {
4541 partition_post_partition_wakeup = ioloop_wakeup_create();
4542 if (partition_post_partition_wakeup == NULL) {
4543 ERROR("partition_post_partition_timeout: can't allocate pref:id wait wakeup.");
4544 return;
4545 }
4546 }
4547 // Allow ten seconds for the services state to settle, after which time we should either have a pref:id backing
4548 // up a prefix, or should advertise a prefix.
4549 INFO("partition_post_partition_timeout: waiting for other BR to publish its prefixes.");
4550 ioloop_add_wake_event(partition_post_partition_wakeup, NULL, partition_post_election_wakeup, NULL, 10 * 1000);
4551 }
4552
4553 static void
4554 partition_proxy_listener_ready(void *__unused context, uint16_t port)
4555 {
4556 INFO("partition_proxy_listener_ready: listening on port %d", port);
4557 srp_service_listen_port = port;
4558 if (have_non_thread_interface) {
4559 partition_can_advertise_service = true;
4560 partition_maybe_advertise_service();
4561 } else {
4562 partition_discontinue_srp_service();
4563 }
4564 }
4565
4566 void
4567 partition_start_srp_listener(void)
4568 {
4569 const int max_avoid_ports = 100;
4570 uint16_t avoid_ports[max_avoid_ports];
4571 int num_avoid_ports = 0;
4572 thread_service_t *service;
4573
4574 for (service = thread_services; service; service = service->next) {
4575 // Track the port regardless.
4576 if (num_avoid_ports < max_avoid_ports) {
4577 avoid_ports[num_avoid_ports] = (service->port[0] << 8) | (service->port[1]);
4578 num_avoid_ports++;
4579 }
4580 }
4581
4582 INFO("partition_start_srp_listener: starting listener.");
4583 srp_listener = srp_proxy_listen("local", avoid_ports, num_avoid_ports, partition_proxy_listener_ready);
4584 if (srp_listener == NULL) {
4585 ERROR("partition_start_srp_listener: Unable to start SRP Proxy listener, so can't advertise it");
4586 return;
4587 }
4588 }
4589
4590 static void
4591 partition_discontinue_srp_service()
4592 {
4593 if (srp_listener != NULL) {
4594 srp_proxy_listener_cancel(srp_listener);
4595 srp_listener = NULL;
4596 }
4597
4598 // Won't match
4599 memset(&srp_listener_ip_address, 0, 16);
4600 srp_service_listen_port = 0;
4601 partition_can_advertise_service = false;
4602
4603 // Stop advertising the service, if we are doing so.
4604 partition_stop_advertising_service();
4605 }
4606
4607 // An address on utun0 has changed. Evaluate what to do with our listener service.
4608 // This gets called from ifaddr_callback(). If we don't yet have a thread service configured,
4609 // it should be called for unchanged addresses as well as changed.
4610 static void
4611 partition_utun0_address_changed(const struct in6_addr *addr, enum interface_address_change change)
4612 {
4613 thread_prefix_t *advertised_prefix = NULL;
4614
4615 // Figure out what our current prefix is.
4616 if (published_thread_prefix != NULL) {
4617 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf);
4618 INFO("partition_utun0_address_changed: advertised prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " is my prefix.",
4619 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf));
4620 advertised_prefix = published_thread_prefix;
4621 } else if (adopted_thread_prefix != NULL) {
4622 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf);
4623 INFO("partition_utun0_address_changed: advertised prefix " PRI_SEGMENTED_IPv6_ADDR_SRP
4624 " is another router's prefix.",
4625 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf));
4626 advertised_prefix = adopted_thread_prefix;
4627 }
4628
4629 SEGMENTED_IPv6_ADDR_GEN_SRP(addr, addr_buf);
4630 // Is this the address we are currently using?
4631 if (!memcmp(&srp_listener_ip_address, addr, 16)) {
4632 // Did it go away? If so, drop the listener.
4633 if (change == interface_address_deleted) {
4634 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP ": listener address removed.",
4635 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4636 if (srp_listener != NULL) {
4637 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4638 ": canceling listener on removed address.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4639 partition_discontinue_srp_service();
4640 }
4641 } else {
4642 // This should never happen.
4643 if (change == interface_address_added) {
4644 ERROR("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4645 ": address we're listening on was added.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4646 }
4647
4648 // Is it on the prefix we're currently publishing?
4649 if (advertised_prefix != NULL && !memcmp(&advertised_prefix->prefix, addr, 8)) {
4650 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4651 ": listener address is on the advertised prefix--no action needed.",
4652 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4653 } else {
4654 // In this case hopefully we'll get a new IP address we _can_ listen on in a subsequent call.
4655 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4656 ": listener address is not on the advertised prefix--no action taken.",
4657 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4658 }
4659 }
4660
4661 // In no case can we do anything further.
4662 return;
4663 }
4664
4665 // If we have a prefix, see if we need to do anything.
4666 if (advertised_prefix != NULL) {
4667 // If this is not the address we are currently using, and it showed up, is it on the prefix we
4668 // are advertising?
4669 if (!memcmp(&advertised_prefix->prefix, addr, 8)) {
4670 // If we are not listening on an address, or we are listening on an address that isn't on the
4671 // prefix we are advertising, we need to stop, if needed, and start up a new listener.
4672 if (srp_listener_ip_address.s6_addr[0] == 0 ||
4673 memcmp(&advertised_prefix->prefix, &srp_listener_ip_address, 8))
4674 {
4675 // See if we already have a listener; if so, stop it.
4676 if (srp_listener_ip_address.s6_addr[0] != 0) {
4677 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP ": stopping old listener.",
4678 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4679 srp_proxy_listener_cancel(srp_listener);
4680 srp_listener = NULL;
4681 }
4682 if (srp_listener == NULL) {
4683 if (!have_non_thread_interface) {
4684 INFO("partition_utun0_address_changed: not starting a listener because we have no infrastructure");
4685 } else {
4686 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP ": starting a new listener.",
4687 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4688 memcpy(&srp_listener_ip_address, addr, 16);
4689 srp_service_listen_port = 0;
4690 partition_start_srp_listener();
4691 }
4692 }
4693 }
4694 } else {
4695 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4696 ": this address not on advertised prefix, so no action to take.",
4697 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4698 }
4699 } else {
4700 INFO("partition_utun0_address_changed: " PRI_SEGMENTED_IPv6_ADDR_SRP
4701 ": no advertised prefix, so no action to take.", SEGMENTED_IPv6_ADDR_PARAM_SRP(addr, addr_buf));
4702 }
4703 }
4704
4705 // We call this function to see if we have a complete, recent set of information; if not, we wait a bit for the set
4706 // to become complete, but after 500ms we assume it won't be and proceed.
4707 static bool
4708 partition_wait_for_prefix_settling(wakeup_callback_t callback, uint64_t now)
4709 {
4710 // Remember when we started waiting for the partition data to settle.
4711 if (partition_settle_satisfied) {
4712 partition_settle_start = now;
4713 partition_settle_satisfied = false;
4714 }
4715
4716 if (partition_settle_wakeup != NULL) {
4717 ioloop_cancel_wake_event(partition_settle_wakeup);
4718 }
4719
4720 // If we aren't able to offer service, just wait.
4721 if (!partition_may_offer_service) {
4722 INFO("partition_wait_for_prefix_settling: not able to offer service--deferring.");
4723 return true;
4724 }
4725
4726 // If we've gotten updates on everything, we're good to go. The reason for comparing against
4727 // partition_settle_start is that if we've been seriously throttled for some reason, it might take
4728 // more than 500ms to get a callback, even though all the events came in between when we asked
4729 // for the initial callback and when we got it. Tunnel ID shouldn't change after startup.
4730 if (partition_last_prefix_set_change >= partition_settle_start &&
4731 partition_last_pref_id_set_change >= partition_settle_start &&
4732 partition_last_partition_id_change >= partition_settle_start &&
4733 partition_last_role_change >= partition_settle_start &&
4734 partition_last_state_change >= partition_settle_start && partition_tunnel_name_is_known)
4735 {
4736 partition_settle_satisfied = true;
4737 INFO("partition_wait_for_prefix_settling: satisfied after %llums.", now - partition_settle_start);
4738 return false; // means don't wait
4739 }
4740
4741 // If we've waited longer than 500ms and aren't satisfied, complain, but then proceed.
4742 if (now - partition_settle_start >= 500) {
4743 ERROR("partition_wait_for_prefix_settling: unsatisfied after %llums", now - partition_settle_start);
4744 partition_settle_satisfied = true; // not really, but there's always next time.
4745 return false; // proceed if possible.
4746 }
4747
4748 // Otherwise, wake up 500ms after we started waiting for things to settle, and reconnoiter.
4749 if (partition_settle_wakeup == NULL) {
4750 partition_settle_wakeup = ioloop_wakeup_create();
4751 if (partition_settle_wakeup == NULL) {
4752 ERROR("partition_wait_for_prefix_settling: Unable to postpone partition settlement wakeup: no memory.");
4753 partition_settle_satisfied = true;
4754 return false;
4755 }
4756 }
4757 ioloop_add_wake_event(partition_settle_wakeup, NULL, callback, NULL, 500 - (int)(now - partition_settle_start));
4758 return true;
4759 }
4760
4761 static void
4762 partition_got_tunnel_name(void)
4763 {
4764 partition_tunnel_name_is_known = true;
4765 refresh_interface_list();
4766 }
4767
4768 // We have a recent prefix list and either have a recent pref:id list or one probably isn't coming.
4769 static void
4770 partition_prefix_list_or_pref_id_list_changed(void *__unused context)
4771 {
4772 // If we haven't had a pref:id update recently, wait a bit to see if one came with the most recent network data.
4773 if (partition_wait_for_prefix_settling(partition_prefix_list_or_pref_id_list_changed, ioloop_timenow())) {
4774 ERROR("partition_prefix_list_or_pref_id_list_changed: waiting for prefix info to settle.");
4775 return;
4776 }
4777
4778 // If we aren't ready to advertise service, do nothing.
4779 if (!partition_may_offer_service) {
4780 INFO("partition_prefix_list_or_pref_id_list_changed can't offer service yet.");
4781 return;
4782 }
4783
4784 // If there are no prefixes, then it doesn't matter what's on the prefix ID list: publish a prefix now.
4785 if (thread_prefixes == NULL) {
4786 INFO("partition_prefix_list_or_pref_id_list_changed have no prefixes, publishing my prefix");
4787 partition_publish_my_prefix();
4788 return;
4789 }
4790
4791 // It is a failure of the thread network software for us to get to this point without knowing the thread
4792 // partition ID. We should have received it on startup. So the case where this would happen would be if
4793 // on startup we simply didn't get it, which should never happen. What we'll do if this happens is make
4794 // one up.
4795 if (partition_id_is_known == false) {
4796 ERROR("partition_prefix_list_or_pref_id_list_changed: partition ID never showed up!");
4797 }
4798
4799 // If we are already publishing a prefix and pref:id, we don't have to do anything to the prefix right now.
4800 if (published_thread_prefix != NULL) {
4801 // We do need to trigger an interface scan though.
4802 refresh_interface_list();
4803
4804 // Also, if there's more than one prefix present, set a timer for an hour from now, at which point we will
4805 // consider dropping our prefix.
4806 if (thread_prefixes != NULL && thread_prefixes->next != NULL) {
4807 INFO("partition_prefix_list_or_pref_id_list_changed:"
4808 "published prefix is unchanged, setting up the pref:id timer");
4809 if (partition_pref_id_wait_wakeup != NULL) {
4810 ioloop_cancel_wake_event(partition_pref_id_wait_wakeup);
4811 } else {
4812 partition_pref_id_wait_wakeup = ioloop_wakeup_create();
4813 if (partition_pref_id_wait_wakeup == NULL) {
4814 ERROR("partition_prefix_list_or_pref_id_list_changed: "
4815 "Unable to set a timer to wake up after the an hour to check the partition id.");
4816 return;
4817 }
4818 }
4819 // The thread network can be pretty chaotic right after the BR comes up, so if we see a partition during the
4820 // first 60 seconds, don't treat it as a real partition event, and do the re-election in 60 seconds rather
4821 // than an hour.
4822 uint64_t time_since_zero = ioloop_timenow() - partition_last_state_change;
4823 uint32_t pref_id_timeout_time = 3600 * 1000;
4824 if (time_since_zero < 60 * 1000) {
4825 pref_id_timeout_time = 60 * 1000;
4826 }
4827 ioloop_add_wake_event(partition_pref_id_wait_wakeup, NULL, partition_pref_id_timeout, NULL,
4828 pref_id_timeout_time);
4829 INFO("added partition pref id timeout");
4830 } else {
4831 INFO("partition_prefix_list_or_pref_id_list_changed: published prefix is unchanged");
4832 }
4833 return;
4834 }
4835
4836 // If we have adopted a prefix and the prefix and pref:id are still present, do nothing.
4837 if (adopted_thread_prefix != NULL) {
4838 if (partition_prefix_is_present(&adopted_thread_prefix->prefix, adopted_thread_prefix->prefix_len) &&
4839 partition_pref_id_is_present(&adopted_thread_prefix->prefix))
4840 {
4841 INFO("partition_prefix_list_or_pref_id_list_changed: adopted prefix is unchanged");
4842 return;
4843 }
4844 // If the adopted prefix is no longer present, stop using it.
4845 partition_unpublish_adopted_prefix(false);
4846 // adopted_thread_prefix is now NULL.
4847 }
4848
4849 // If there is a prefix present for which there is already a matching pref:id, adopt that prefix and pref:id now.
4850 // drop the thread_post_partition_timeout timer.
4851 thread_prefix_t *prefix;
4852 for (prefix = thread_prefixes; prefix; prefix = prefix->next) {
4853 if (partition_pref_id_is_present(&prefix->prefix)) {
4854 INFO("partition_prefix_list_or_pref_id_list_changed: adopting new prefix");
4855 partition_adopt_prefix(prefix);
4856 // When we adopt a prefix, it was already on-link, and quite possibly we already have an address
4857 // configured on that prefix on utun0. Calling refresh_interface_list() will trigger the listener
4858 // if in fact that's the case. If the address hasn't come up on utun0 yet, then when it comes up
4859 // that will trigger the listener.
4860 refresh_interface_list();
4861 return;
4862 }
4863 if (partition_post_partition_wakeup != NULL) {
4864 ioloop_cancel_wake_event(partition_post_partition_wakeup);
4865 }
4866 }
4867
4868 // At this point there is a prefix, but no pref:id, and it's /not/ the prefix that we published. This
4869 // means that a partition has happened and the BR that published the prefix is on the other partition,
4870 // or else that the BR that published the prefix has gone offline and has been offline for at least
4871 // four minutes.
4872 // It's possible that either condition will heal, but in the meantime publish a prefix. The reason for
4873 // the urgency is that if we have a partition, and both routers are still online, then routing will be
4874 // screwed up until we publish a new prefix and migrate all the accessories on our partition to the
4875 // new prefix.
4876 INFO("partition_publish_prefix: there is a prefix, but no pref:id, so it's stale. Publishing my prefix.");
4877 partition_publish_my_prefix();
4878 }
4879
4880 // The list of published prefix has changed. Evaluate what to do with our partition state.
4881 // Mostly what we do when the prefix list changes is the same as what we do if the pref:id list
4882 // changes, but if we get an empty prefix list, it doesn't matter what's on the pref:id list,
4883 // so we act immediately.
4884 static void
4885 partition_prefix_set_changed(void)
4886 {
4887 // Time stamp most recent prefix set update.
4888 partition_last_prefix_set_change = ioloop_timenow();
4889
4890 // Otherwise, we have a prefix list and a pref:id list, so we can make decisions.
4891 partition_prefix_list_or_pref_id_list_changed(NULL);
4892 }
4893
4894 // The set of published pref:id's changed. Evaluate what to do with our pref:id
4895 static void
4896 partition_pref_id_set_changed(void)
4897 {
4898 // Time stamp most recent prefix set update.
4899 partition_last_prefix_set_change = ioloop_timenow();
4900
4901 // Otherwise, we have a prefix list and a pref:id list, so we can make decisions.
4902 partition_prefix_list_or_pref_id_list_changed(NULL);
4903 }
4904
4905 // The partition ID changed.
4906 static void
4907 partition_id_changed(void)
4908 {
4909 partition_last_partition_id_change = ioloop_timenow();
4910
4911 // If we've never seen a partition ID before, this is not (necessarily) a partition.
4912 if (!partition_id_is_known) {
4913 INFO("partition_id_changed: first time through.");
4914 partition_id_is_known = true;
4915 return;
4916 }
4917
4918 // If we get a partition ID when we aren't a router, we should (I think!) ignore it.
4919 if (!partition_can_provide_routing) {
4920 INFO("partition_id_changed: we aren't able to offer routing yet, so ignoring.");
4921 return;
4922 }
4923
4924 // If we are advertising a prefix, update our pref:id
4925 if (published_thread_prefix != NULL) {
4926 INFO("partition_id_changed: updating advertised prefix id");
4927 partition_id_update();
4928 // In principle we didn't change anything material to the routing subsystem, so no need to re-evaluate current
4929 // policy.
4930 return;
4931 }
4932
4933 // Propose our prefix as a possible lowest prefix in case there's an election.
4934 partition_stop_advertising_pref_id();
4935 partition_advertise_pref_id(((uint8_t *)(&my_thread_prefix)) + 1);
4936
4937 // If we have adopted a prefix, set a timer after which we will drop it and start advertising if nothing has
4938 // happened
4939 if (partition_post_partition_wakeup != NULL) {
4940 ioloop_cancel_wake_event(partition_post_partition_wakeup);
4941 } else {
4942 partition_post_partition_wakeup = ioloop_wakeup_create();
4943 if (partition_post_partition_wakeup == NULL) {
4944 ERROR("partition_id_changed: can't allocate pref:id wait wakeup.");
4945 return;
4946 }
4947 }
4948 // Allow ten seconds for the services state to settle, after which time we should either have a pref:id backing
4949 // up a prefix, or should advertise a prefix.
4950 INFO("partition_id_changed: waiting for other BRs to propose their prefixes.");
4951 ioloop_add_wake_event(partition_post_partition_wakeup, NULL, partition_post_partition_timeout, NULL, 10 * 1000);
4952 }
4953
4954 static void
4955 partition_remove_service_done(void *context, cti_status_t status)
4956 {
4957 INFO("partition_remove_service_done: %d", status);
4958
4959 // Flush any advertisements we're currently doing, since the accessories that advertised them will
4960 // notice the service is gone and start advertising with a different service.
4961 #ifndef OPEN_SOURCE
4962 // The conditional test is so that we don't do this twice when we are advertising both services.
4963 #endif
4964 if (context != NULL) {
4965 srp_mdns_flush();
4966 }
4967 }
4968
4969 static void
4970 partition_stop_advertising_service(void)
4971 {
4972 // This should remove any copy of the service that this BR is advertising.
4973 INFO("partition_stop_advertising_service: %" PRIu64 "/" PUB_S_SRP, THREAD_ENTERPRISE_NUMBER, "00010001");
4974 uint8_t service_info[] = { 0, 0, 0, 1 };
4975 int status;
4976
4977 service_info[0] = THREAD_SRP_SERVER_OPTION & 255;
4978 status = cti_remove_service((void *)(ptrdiff_t)1, partition_remove_service_done, dispatch_get_main_queue(),
4979 THREAD_ENTERPRISE_NUMBER, service_info, 1);
4980 if (status != kCTIStatus_NoError) {
4981 INFO("partition_stop_advertising_service: status %d", status);
4982 }
4983 }
4984
4985 static void
4986 partition_add_service_callback(void *__unused context, cti_status_t status)
4987 {
4988 if (status != kCTIStatus_NoError) {
4989 INFO("partition_add_service_callback: status = %d", status);
4990 } else {
4991 INFO("partition_add_service_callback: status = %d", status);
4992 }
4993 }
4994
4995 static void
4996 partition_start_advertising_service(void)
4997 {
4998 uint8_t service_info[] = {0, 0, 0, 1};
4999 uint8_t server_info[18];
5000 int ret;
5001
5002 memcpy(&server_info, &srp_listener_ip_address, 16);
5003 server_info[16] = (srp_service_listen_port >> 8) & 255;
5004 server_info[17] = srp_service_listen_port & 255;
5005
5006 service_info[0] = THREAD_SRP_SERVER_OPTION & 255;
5007 INFO("partition_add_srp_service: %" PRIu64 "/%02x/" PRI_SEGMENTED_IPv6_ADDR_SRP ":%d" ,
5008 THREAD_ENTERPRISE_NUMBER, service_info[0],
5009 SEGMENTED_IPv6_ADDR_PARAM_SRP(srp_listener_ip_address.s6_addr, server_ip_buf), srp_service_listen_port);
5010
5011 ret = cti_add_service(NULL, partition_add_service_callback, dispatch_get_main_queue(),
5012 THREAD_ENTERPRISE_NUMBER, service_info, 1, server_info, sizeof server_info);
5013 if (ret != kCTIStatus_NoError) {
5014 INFO("partition_add_srp_service: status %d", ret);
5015 }
5016
5017 // Wait a while for the service add to be reflected in an event.
5018 partition_schedule_service_add_wakeup();
5019 }
5020
5021 static void
5022 partition_service_add_wakeup(void *__unused context)
5023 {
5024 partition_service_last_add_time = 0;
5025 partition_maybe_advertise_service();
5026 }
5027
5028 static void
5029 partition_schedule_service_add_wakeup()
5030 {
5031 if (partition_service_add_pending_wakeup == NULL) {
5032 partition_service_add_pending_wakeup = ioloop_wakeup_create();
5033 if (partition_service_add_pending_wakeup == NULL) {
5034 ERROR("Can't schedule service add pending wakeup: no memory!");
5035 return;
5036 }
5037 } else {
5038 ioloop_cancel_wake_event(partition_service_add_pending_wakeup);
5039 }
5040 // Wait ten seconds.
5041 ioloop_add_wake_event(partition_service_add_pending_wakeup, NULL, partition_service_add_wakeup, NULL, 10 * 1000);
5042 }
5043
5044 static void
5045 partition_maybe_advertise_service(void)
5046 {
5047 thread_service_t *service, *lowest[2];
5048 int num_services = 0;
5049 int i;
5050 bool should_remove_service = false;
5051 bool should_advertise_service = false;
5052 int64_t last_add_time;
5053
5054 // If we aren't ready to advertise a service, there's nothing to do.
5055 if (!partition_can_advertise_service) {
5056 INFO("partition_maybe_advertise_service: no service to advertise yet.");
5057 return;
5058 }
5059
5060 if (partition_service_blocked) {
5061 INFO("partition_maybe_advertise_service: service advertising is disabled.");
5062 return;
5063 }
5064
5065 for (i = 0; i < 16; i++) {
5066 if (srp_listener_ip_address.s6_addr[i] != 0) {
5067 break;
5068 }
5069 }
5070 if (i == 16) {
5071 INFO("partition_maybe_advertise_service: no listener.");
5072 return;
5073 }
5074
5075 // The add service function requires a remove prior to the add, so if we are doing an add, we need to wait
5076 // for things to stabilize before allowing the removal of a service to trigger a re-evaluation.
5077 // Therefore, if we've done an add in the past ten seconds, wait ten seconds before trying another add.
5078 last_add_time = ioloop_timenow() - partition_service_last_add_time;
5079 INFO("partition_maybe_advertise_service: last_add_time = %" PRId64, last_add_time);
5080 if (last_add_time < 10 * 1000) {
5081 partition_schedule_service_add_wakeup();
5082 return;
5083 }
5084 lowest[0] = NULL;
5085 lowest[1] = NULL;
5086
5087 for (service = thread_services; service; service = service->next) {
5088 int port = service->port[0] | (service->port[1] << 8);
5089 SEGMENTED_IPv6_ADDR_GEN_SRP(service->address, srv_addr_buf);
5090
5091 // A service only counts if its prefix is present and its prefix id is present and matches the
5092 // current partition id.
5093 if (partition_prefix_is_present((struct in6_addr *)service->address, 64)) {
5094 if (partition_pref_id_is_present((struct in6_addr *)service->address)) {
5095 num_services++;
5096 for (i = 0; i < 2; i++) {
5097 if (lowest[i] == NULL) {
5098 lowest[i] = service;
5099 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d goes in open slot %d.",
5100 SEGMENTED_IPv6_ADDR_PARAM_SRP(service->address, srv_addr_buf), port, i);
5101 break;
5102 } else if (memcmp(service->address, lowest[i]->address, 16) < 0) {
5103 int lowport;
5104
5105 if (lowest[1] != NULL) {
5106 lowport = (lowest[1]->port[0] << 8) | lowest[1]->port[1];
5107 SEGMENTED_IPv6_ADDR_GEN_SRP(lowest[1]->address, lowest_1_buf);
5108 INFO("Superseding " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d in slot 1",
5109 SEGMENTED_IPv6_ADDR_PARAM_SRP(lowest[1]->address, lowest_1_buf), lowport);
5110 }
5111 if (i == 0) {
5112 lowport = (lowest[0]->port[0] << 8)| lowest[0]->port[1];
5113 SEGMENTED_IPv6_ADDR_GEN_SRP(lowest[0]->address, lowest_0_buf);
5114 INFO("Moving " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d from slot 0 to slot 1",
5115 SEGMENTED_IPv6_ADDR_PARAM_SRP(lowest[0]->address, lowest_0_buf), lowport);
5116 lowest[1] = lowest[0];
5117 }
5118 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d goes in slot %d.",
5119 SEGMENTED_IPv6_ADDR_PARAM_SRP(service->address, srv_addr_buf), port, i);
5120 lowest[i] = service;
5121 break;
5122 }
5123 }
5124 } else {
5125 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d doesn't count because the pref:id is not present.",
5126 SEGMENTED_IPv6_ADDR_PARAM_SRP(service->address, srv_addr_buf), port);
5127 }
5128 } else {
5129 INFO("service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d doesn't count because the prefix is not present.",
5130 SEGMENTED_IPv6_ADDR_PARAM_SRP(service->address, srv_addr_buf), port);
5131 }
5132 }
5133
5134 should_remove_service = true;
5135 for (i = 0; i < 2; i++) {
5136 if (lowest[i] == NULL) {
5137 INFO("partition_maybe_advertise_service: adding service because there's an open slot.");
5138 should_remove_service = false;
5139 should_advertise_service = true;
5140 break;
5141 } else {
5142 int sign = memcmp(((uint8_t *)(&srp_listener_ip_address)), lowest[i]->address, 16);
5143 if (sign == 0) {
5144 // We're already advertising the service and we win the election.
5145 // If the port hasn't changed, don't update the service
5146 uint16_t port = (lowest[i]->port[0] << 8) | lowest[i]->port[1];
5147 if (port != srp_service_listen_port) {
5148 INFO("partition_maybe_advertise_service: old service was present and prefix would win election.");
5149 should_remove_service = false;
5150 should_advertise_service = true;
5151 } else {
5152 INFO("partition_maybe_advertise_service: service already present and would win election.");
5153 should_remove_service = false;
5154 should_advertise_service = false;
5155 }
5156 break;
5157 } else if (sign < 0) {
5158 INFO("partition_maybe_advertise_service: service not present but wins election.");
5159 should_remove_service = false;
5160 should_advertise_service = true;
5161 break;
5162 } else {
5163 INFO("Service would not win election with lowest[%d]", i);
5164 }
5165 }
5166 }
5167
5168 // Always remove service before adding it, but also remove it if it lost the election.
5169 if (should_remove_service) {
5170 partition_stop_advertising_service();
5171 partition_service_last_add_time = ioloop_timenow();
5172 }
5173 if (should_advertise_service) {
5174 partition_start_advertising_service();
5175 partition_service_last_add_time = ioloop_timenow();
5176 }
5177 }
5178
5179 static void
5180 partition_service_set_changed()
5181 {
5182 partition_pref_id_set_changed();
5183 partition_maybe_advertise_service();
5184 }
5185
5186 static void partition_maybe_enable_services()
5187 {
5188 bool am_associated = current_thread_state == kCTI_NCPState_Associated;
5189 if (am_associated) {
5190 INFO("partition_maybe_enable_services: "
5191 "Enabling service, which was disabled because of the thread role or state.");
5192 partition_may_offer_service = true;
5193 partition_can_provide_routing = true;
5194 refresh_interface_list();
5195 partition_prefix_list_or_pref_id_list_changed(NULL);
5196 routing_policy_evaluate_all_interfaces(true);
5197 } else {
5198 INFO("partition_maybe_enable_services: Not enabling service: " PUB_S_SRP,
5199 am_associated ? "associated" : "!associated");
5200 }
5201 }
5202
5203 static void partition_disable_service()
5204 {
5205 bool done_something = false;
5206
5207 // When our node type or state is such that we should no longer be publishing a prefix, the NCP will
5208 // automatically remove the published prefix. In case this happens, we do not want to remember the
5209 // prefix as already having been published. So drop our recollection of the adopted and published
5210 // prefixes; this will get cleaned up when the network comes back if there's an inconsistency.
5211 if (adopted_thread_prefix != NULL) {
5212 SEGMENTED_IPv6_ADDR_GEN_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf);
5213 INFO("partition_disable_service: unadopting prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
5214 SEGMENTED_IPv6_ADDR_PARAM_SRP(adopted_thread_prefix->prefix.s6_addr, prefix_buf));
5215 RELEASE_HERE(adopted_thread_prefix, thread_prefix_finalize);
5216 adopted_thread_prefix = NULL;
5217 done_something = true;
5218 }
5219 if (published_thread_prefix != NULL) {
5220 SEGMENTED_IPv6_ADDR_GEN_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf);
5221 INFO("partition_disable_service: un-publishing prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
5222 SEGMENTED_IPv6_ADDR_PARAM_SRP(published_thread_prefix->prefix.s6_addr, prefix_buf));
5223 RELEASE_HERE(published_thread_prefix, thread_prefix_finalize);
5224 published_thread_prefix = NULL;
5225 done_something = true;
5226 }
5227
5228 // We want to always say something when we pass through this state.
5229 if (!done_something) {
5230 INFO("partition_disable_service: nothing to do.");
5231 }
5232
5233 partition_may_offer_service = false;
5234 partition_can_provide_routing = false;
5235 }
5236 #endif // RA_TESTER
5237
5238 // Local Variables:
5239 // mode: C
5240 // tab-width: 4
5241 // c-file-style: "bsd"
5242 // c-basic-offset: 4
5243 // fill-column: 120
5244 // indent-tabs-mode: nil
5245 // End: