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