]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/eventmon.c
configd-1109.101.1.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
1 /*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * December 3, 2002 Dieter Siegmund <dieter@apple.com>
28 * - handle the new KEV_INET_ARPCOLLISION event
29 * - format the event into a DynamicStore key
30 * State:/Network/Interface/ifname/IPv4Collision/ip_addr/hw_addr
31 * and send a notification on the key
32 *
33 * August 8, 2002 Allan Nathanson <ajn@apple.com>
34 * - added support for KEV_INET6_xxx events
35 *
36 * January 6, 2002 Jessica Vazquez <vazquez@apple.com>
37 * - added handling for KEV_ATALK_xxx events
38 *
39 * July 2, 2001 Dieter Siegmund <dieter@apple.com>
40 * - added handling for KEV_DL_PROTO_{ATTACHED, DETACHED}
41 * - mark an interface up if the number of protocols remaining is not 0,
42 * mark an interface down if the number is zero
43 * - allocate socket on demand instead of keeping it open all the time
44 *
45 * June 23, 2001 Allan Nathanson <ajn@apple.com>
46 * - update to public SystemConfiguration.framework APIs
47 *
48 * May 17, 2001 Allan Nathanson <ajn@apple.com>
49 * - add/maintain per-interface address/netmask/destaddr information
50 * in the dynamic store.
51 *
52 * June 30, 2000 Allan Nathanson <ajn@apple.com>
53 * - initial revision
54 */
55
56 #include "eventmon.h"
57 #include "ev_dlil.h"
58 #include "ev_ipv4.h"
59 #include "ev_ipv6.h"
60 #include <notify.h>
61 #include <sys/sysctl.h>
62 #include <sys/kern_event.h>
63 #include <nw/private.h>
64 #include <netinet6/nd6.h>
65
66 static dispatch_queue_t S_kev_queue;
67 static dispatch_source_t S_kev_source;
68 __private_extern__ Boolean network_changed = FALSE;
69 __private_extern__ SCDynamicStoreRef store = NULL;
70 __private_extern__ Boolean _verbose = FALSE;
71
72
73 __private_extern__ os_log_t
74 __log_KernelEventMonitor(void)
75 {
76 static os_log_t log = NULL;
77
78 if (log == NULL) {
79 log = os_log_create("com.apple.SystemConfiguration", "KernelEventMonitor");
80 }
81
82 return log;
83 }
84
85
86 #define MESSAGES_MAX 100
87 static CFMutableArrayRef S_messages;
88 static Boolean S_messages_modified;
89
90 static void
91 messages_init(void)
92 {
93 S_messages = CFArrayCreateMutable(NULL,
94 0,
95 &kCFTypeArrayCallBacks);
96 return;
97 }
98
99 static void
100 messages_free(void)
101 {
102 if (S_messages != NULL) {
103 CFRelease(S_messages);
104 S_messages = NULL;
105 }
106 return;
107 }
108
109 static Boolean
110 messages_should_add_message(void)
111 {
112 if (S_messages == NULL
113 || CFArrayGetCount(S_messages) >= MESSAGES_MAX) {
114 return (FALSE);
115 }
116 return (TRUE);
117 }
118
119 static void
120 messages_add_message(CFStringRef message)
121 {
122 if (messages_should_add_message()) {
123 CFArrayAppendValue(S_messages, message);
124 S_messages_modified = TRUE;
125 }
126 return;
127 }
128
129 __private_extern__ void
130 messages_add_msg_with_arg(const char * msg, const char * arg)
131 {
132 if (messages_should_add_message()) {
133 CFStringRef str;
134
135 str = CFStringCreateWithFormat(NULL, NULL,
136 CFSTR("%12.8f: %s %s"),
137 CFAbsoluteTimeGetCurrent(),
138 msg, arg);
139 messages_add_message(str);
140 CFRelease(str);
141 }
142 return;
143 }
144
145 static void
146 messages_post(void)
147 {
148 if (S_messages != NULL && S_messages_modified) {
149 SCDynamicStoreSetValue(NULL,
150 CFSTR("Plugin:KernelEventMonitor"),
151 S_messages);
152 S_messages_modified = FALSE;
153 }
154 return;
155 }
156
157 static void
158 check_interface_link_status(const char * if_name)
159 {
160 if (S_messages == NULL) {
161 return; /* we're not in early boot of system */
162 }
163 link_update_status_if_missing(if_name);
164 return;
165 }
166
167 __private_extern__
168 int
169 dgram_socket(int domain)
170 {
171 int s;
172
173 s = socket(domain, SOCK_DGRAM, 0);
174 if (s == -1) {
175 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
176 }
177
178 return s;
179 }
180
181 static void
182 post_network_changed(void)
183 {
184 if (network_changed) {
185 uint32_t status;
186
187 status = notify_post(_SC_NOTIFY_NETWORK_CHANGE);
188 if (status != NOTIFY_STATUS_OK) {
189 SC_log(LOG_NOTICE, "notify_post() failed: error=%u", status);
190 }
191
192 network_changed = FALSE;
193 }
194
195 return;
196 }
197
198 static void
199 logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
200 {
201 int i;
202 uint32_t j;
203
204 if (!_verbose) {
205 return;
206 }
207
208 SC_log(LOG_DEBUG, "%@ event:", evStr);
209 SC_log(LOG_DEBUG, " Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d",
210 ev_msg->total_size,
211 ev_msg->id,
212 ev_msg->vendor_code,
213 ev_msg->kev_class,
214 ev_msg->kev_subclass,
215 ev_msg->event_code);
216 for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
217 SC_log(LOG_DEBUG, " Event data[%2d] = %08x", i, ev_msg->event_data[i]);
218 }
219 }
220
221 static void
222 copy_if_name(const struct net_event_data * ev, char * ifr_name, int ifr_len)
223 {
224 snprintf(ifr_name, ifr_len, "%s%d", ev->if_name, ev->if_unit);
225 return;
226 }
227
228 static uint8_t info_zero[DLIL_MODARGLEN];
229
230 static void
231 processEvent_Apple_Network(struct kern_event_msg *ev_msg)
232 {
233 size_t dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
234 void * event_data = &ev_msg->event_data[0];
235 char ifr_name[IFNAMSIZ];
236 Boolean handled = TRUE;
237
238 switch (ev_msg->kev_subclass) {
239 case KEV_INET_SUBCLASS : {
240 switch (ev_msg->event_code) {
241 case KEV_INET_NEW_ADDR :
242 case KEV_INET_CHANGED_ADDR :
243 case KEV_INET_ADDR_DELETED :
244 case KEV_INET_SIFDSTADDR :
245 case KEV_INET_SIFBRDADDR :
246 case KEV_INET_SIFNETMASK : {
247 struct kev_in_data * ev;
248
249 ev = (struct kev_in_data *)event_data;
250 if (dataLen < sizeof(*ev)) {
251 handled = FALSE;
252 break;
253 }
254 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
255 SC_log(LOG_INFO, "Process IPv4 address change: %s: %d", (char *)ifr_name, ev_msg->event_code);
256 ipv4_interface_update(NULL, ifr_name);
257 if (ev_msg->event_code
258 != KEV_INET_ADDR_DELETED) {
259 check_interface_link_status(ifr_name);
260 }
261 break;
262 }
263 case KEV_INET_ARPCOLLISION : {
264 struct kev_in_collision * ev;
265
266 ev = (struct kev_in_collision *)event_data;
267 if ((dataLen < sizeof(*ev))
268 || (dataLen < (sizeof(*ev) + ev->hw_len))) {
269 handled = FALSE;
270 break;
271 }
272 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
273 SC_log(LOG_INFO, "Process ARP collision: %s", (char *)ifr_name);
274 ipv4_arp_collision(ifr_name,
275 ev->ia_ipaddr,
276 ev->hw_len,
277 ev->hw_addr);
278 break;
279 }
280 #if !TARGET_OS_IPHONE
281 case KEV_INET_PORTINUSE : {
282 struct kev_in_portinuse * ev;
283 ev = (struct kev_in_portinuse *)event_data;
284 if (dataLen < sizeof(*ev)) {
285 handled = FALSE;
286 break;
287 }
288 SC_log(LOG_INFO, "Process port-in-use: %hu, %u", ev->port, ev->req_pid);
289 ipv4_port_in_use(ev->port, ev->req_pid);
290 break;
291 }
292 #endif /* !TARGET_OS_IPHONE */
293 case KEV_INET_ARPRTRFAILURE: {
294 const struct kev_in_arpfailure * ev;
295
296 ev = (const struct kev_in_arpfailure *)event_data;
297 if (dataLen < sizeof(*ev)) {
298 handled = FALSE;
299 break;
300 }
301 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
302 SC_log(LOG_INFO, "Process router ARP failure: %s", (char *)ifr_name);
303 ipv4_router_arp_failure(ifr_name);
304 break;
305 }
306 case KEV_INET_ARPRTRALIVE: {
307 const struct kev_in_arpalive * ev;
308
309 ev = (const struct kev_in_arpalive *)event_data;
310 if (dataLen < sizeof(*ev)) {
311 handled = FALSE;
312 break;
313 }
314 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
315 SC_log(LOG_INFO, "Process router ARP alive: %s", (char *)ifr_name);
316 ipv4_router_arp_alive(ifr_name);
317 break;
318 }
319 default :
320 break;
321 }
322 break;
323 }
324
325 case KEV_INET6_SUBCLASS : {
326 struct kev_in6_data * ev;
327
328 ev = (struct kev_in6_data *)event_data;
329 switch (ev_msg->event_code) {
330 case KEV_INET6_NEW_USER_ADDR :
331 case KEV_INET6_CHANGED_ADDR :
332 case KEV_INET6_ADDR_DELETED :
333 case KEV_INET6_NEW_LL_ADDR :
334 case KEV_INET6_NEW_RTADV_ADDR :
335 if (dataLen < sizeof(*ev)) {
336 handled = FALSE;
337 break;
338 }
339 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
340 SC_log(LOG_INFO, "Process IPv6 address change: %s: %d", (char *)ifr_name, ev_msg->event_code);
341 interface_update_ipv6(NULL, ifr_name);
342 if (ev_msg->event_code == KEV_INET6_NEW_USER_ADDR
343 && (ev->ia6_flags & IN6_IFF_DUPLICATED) != 0) {
344 ipv6_duplicated_address(ifr_name,
345 &ev->ia_addr.sin6_addr,
346 ETHER_ADDR_LEN,
347 &ev->ia_mac);
348 }
349 if (ev_msg->event_code
350 != KEV_INET6_ADDR_DELETED) {
351 check_interface_link_status(ifr_name);
352 }
353 break;
354
355 case KEV_INET6_REQUEST_NAT64_PREFIX :
356 if (dataLen < sizeof(*ev)) {
357 handled = FALSE;
358 break;
359 }
360 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
361 SC_log(LOG_INFO, "Process NAT64 prefix request: %s", (char *)ifr_name);
362 nat64_prefix_request(ifr_name);
363 break;
364
365 default :
366 break;
367 }
368 break;
369 }
370
371 case KEV_DL_SUBCLASS : {
372 struct net_event_data * ev;
373
374 ev = (struct net_event_data *)event_data;
375 switch (ev_msg->event_code) {
376 case KEV_DL_IF_ATTACHED :
377 /*
378 * new interface added
379 */
380 if (dataLen < sizeof(*ev)) {
381 handled = FALSE;
382 break;
383 }
384 copy_if_name(ev, ifr_name, sizeof(ifr_name));
385 SC_log(LOG_INFO, "Process interface attach: %s", (char *)ifr_name);
386 link_add(ifr_name);
387 break;
388
389 case KEV_DL_IF_DETACHED :
390 /*
391 * interface removed
392 */
393 if (dataLen < sizeof(*ev)) {
394 handled = FALSE;
395 break;
396 }
397 copy_if_name(ev, ifr_name, sizeof(ifr_name));
398 SC_log(LOG_INFO, "Process interface detach: %s", (char *)ifr_name);
399 link_remove(ifr_name);
400 break;
401
402 case KEV_DL_IF_DETACHING :
403 /*
404 * interface detaching
405 */
406 if (dataLen < sizeof(*ev)) {
407 handled = FALSE;
408 break;
409 }
410 copy_if_name(ev, ifr_name, sizeof(ifr_name));
411 SC_log(LOG_INFO, "Process interface detaching: %s", (char *)ifr_name);
412 interface_detaching(ifr_name);
413 break;
414
415 case KEV_DL_PROTO_ATTACHED :
416 case KEV_DL_PROTO_DETACHED : {
417 struct kev_dl_proto_data * protoEvent;
418
419 protoEvent = (struct kev_dl_proto_data *)event_data;
420 if (dataLen < sizeof(*protoEvent)) {
421 handled = FALSE;
422 break;
423 }
424 copy_if_name(&protoEvent->link_data,
425 ifr_name, sizeof(ifr_name));
426 SC_log(LOG_INFO, "Process protocol %s: %s (pf=%d, n=%d)",
427 (ev_msg->event_code == KEV_DL_PROTO_ATTACHED) ? "attach" : "detach",
428 (char *)ifr_name,
429 protoEvent->proto_family,
430 protoEvent->proto_remaining_count);
431 break;
432 }
433
434 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
435 case KEV_DL_IF_IDLE_ROUTE_REFCNT: {
436 /*
437 * interface route refcnt idle
438 */
439 if (dataLen < sizeof(*ev)) {
440 handled = FALSE;
441 break;
442 }
443 copy_if_name(ev, ifr_name, sizeof(ifr_name));
444 SC_log(LOG_INFO, "Process interface idle: %s", (char *)ifr_name);
445 interface_update_idle_state(ifr_name);
446 break;
447 }
448 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
449
450 case KEV_DL_IFDELEGATE_CHANGED: {
451 /*
452 * interface delegation changed
453 */
454 if (dataLen < sizeof(*ev)) {
455 handled = FALSE;
456 break;
457 }
458 copy_if_name(ev, ifr_name, sizeof(ifr_name));
459 SC_log(LOG_INFO, "Process interface delegation change: %s", (char *)ifr_name);
460 interface_update_delegation(ifr_name);
461 break;
462 }
463
464 case KEV_DL_LINK_OFF :
465 case KEV_DL_LINK_ON :
466 /*
467 * update the link status in the store
468 */
469 if (dataLen < sizeof(*ev)) {
470 handled = FALSE;
471 break;
472 }
473 copy_if_name(ev, ifr_name, sizeof(ifr_name));
474 SC_log(LOG_INFO, "Process interface link %s: %s",
475 (ev_msg->event_code == KEV_DL_LINK_ON) ? "up" : "down",
476 (char *)ifr_name);
477 link_update_status(ifr_name, FALSE, FALSE);
478 break;
479
480 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
481 case KEV_DL_LINK_QUALITY_METRIC_CHANGED: {
482 struct kev_dl_link_quality_metric_data * lqm_data;
483 lqm_data = (struct kev_dl_link_quality_metric_data *) event_data;
484
485 if (dataLen < sizeof(*ev)) {
486 handled = FALSE;
487 break;
488 }
489 copy_if_name(ev, ifr_name, sizeof(ifr_name));
490 SC_log(LOG_INFO, "Process interface quality: %s (q=%d)",
491 (char *)ifr_name,
492 lqm_data->link_quality_metric);
493 interface_update_quality_metric(ifr_name,
494 lqm_data->link_quality_metric);
495 break;
496 }
497 #endif // KEV_DL_LINK_QUALITY_METRIC_CHANGED
498
499 #ifdef KEV_DL_ISSUES
500 case KEV_DL_ISSUES: {
501 struct kev_dl_issues *issues;
502
503 issues = (struct kev_dl_issues *)event_data;
504 if (dataLen < sizeof(*ev)) {
505 handled = FALSE;
506 break;
507 }
508 copy_if_name(ev, ifr_name, sizeof(ifr_name));
509 SC_log(LOG_INFO, "Process interface link issues: %s",
510 (char *)ifr_name);
511 interface_update_link_issues(ifr_name,
512 issues->timestamp,
513 issues->modid,
514 DLIL_MODIDLEN,
515 issues->info,
516 (bcmp(issues->info, info_zero, DLIL_MODARGLEN) != 0)
517 ? DLIL_MODARGLEN
518 : 0);
519 break;
520 }
521 #endif // KEV_DL_ISSUES
522
523 default :
524 break;
525 }
526 break;
527 }
528
529 #ifdef KEV_NETPOLICY_SUBCLASS
530 case KEV_NETPOLICY_SUBCLASS : {
531 break;
532 }
533 #endif // KEV_NETPOLICY_SUBCLASS
534
535 #ifdef KEV_SOCKET_SUBCLASS
536 case KEV_SOCKET_SUBCLASS : {
537 break;
538 }
539 #endif // KEV_SOCKET_SUBCLASS
540
541 #ifdef KEV_ND6_SUBCLASS
542 case KEV_ND6_SUBCLASS : {
543 struct kev_nd6_event * ev;
544
545 ev = (struct kev_nd6_event *)event_data;
546 switch (ev_msg->event_code) {
547 case KEV_ND6_ADDR_DETACHED :
548 case KEV_ND6_ADDR_DEPRECATED :
549 case KEV_ND6_ADDR_EXPIRED :
550 if (dataLen < sizeof(*ev)) {
551 handled = FALSE;
552 break;
553 }
554 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
555 SC_log(LOG_INFO, "Process ND6 address change: %s: %d", (char *)ifr_name, ev_msg->event_code);
556 interface_update_ipv6(NULL, ifr_name);
557 break;
558 case KEV_ND6_RTR_EXPIRED :
559 if (dataLen < sizeof(*ev)) {
560 handled = FALSE;
561 break;
562 }
563 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
564 SC_log(LOG_INFO, "Process IPv6 router expired: %s: %d", (char *)ifr_name, ev_msg->event_code);
565 ipv6_router_expired(ifr_name);
566 break;
567 default :
568 break;
569 }
570 break;
571 }
572 #endif // KEV_ND6_SUBCLASS
573
574 #ifdef KEV_NECP_SUBCLASS
575 case KEV_NECP_SUBCLASS : {
576 break;
577 }
578 #endif // KEV_NECP_SUBCLASS
579
580 #ifdef KEV_NETAGENT_SUBCLASS
581 case KEV_NETAGENT_SUBCLASS : {
582 break;
583 }
584 #endif // KEV_NETAGENT_SUBCLASS
585
586 #ifdef KEV_LOG_SUBCLASS
587 case KEV_LOG_SUBCLASS : {
588 break;
589 }
590 #endif // KEV_LOG_SUBCLASS
591
592 #ifdef KEV_NETEVENT_SUBCLASS
593 case KEV_NETEVENT_SUBCLASS : {
594 break;
595 }
596 #endif // KEV_NETEVENT_SUBCLASS
597
598 default :
599 break;
600 }
601
602 if (!handled) {
603 logEvent(CFSTR("Error processing (Apple network subclass)"), ev_msg);
604 }
605 return;
606 }
607
608 static Boolean
609 eventCallback(int so)
610 {
611 union {
612 char bytes[1024];
613 struct kern_event_msg ev_msg1; // first kernel event
614 } buf;
615 struct kern_event_msg *ev_msg = &buf.ev_msg1;
616 ssize_t offset = 0;
617 ssize_t status;
618
619 status = recv(so, &buf, sizeof(buf), 0);
620 if (status == -1) {
621 SC_log(LOG_NOTICE, "recv() failed: %s", strerror(errno));
622 return FALSE;
623 }
624
625 _SCDynamicStoreCacheOpen(store);
626
627 while (offset < status) {
628 if ((offset + (ssize_t)ev_msg->total_size) > status) {
629 SC_log(LOG_NOTICE, "missed SYSPROTO_EVENT event, buffer not big enough");
630 break;
631 }
632
633 switch (ev_msg->vendor_code) {
634 case KEV_VENDOR_APPLE :
635 switch (ev_msg->kev_class) {
636 case KEV_NETWORK_CLASS :
637 processEvent_Apple_Network(ev_msg);
638 break;
639
640 default :
641 break;
642 }
643 break;
644 default :
645 break;
646 }
647 offset += ev_msg->total_size;
648 ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset];
649 }
650
651 _SCDynamicStoreCacheCommitChanges(store);
652 _SCDynamicStoreCacheClose(store);
653 post_network_changed();
654 messages_post();
655
656 return TRUE;
657 }
658
659
660 __private_extern__ void
661 config_new_interface(const char * ifname)
662 {
663 xpc_object_t if_list;
664
665 if (ifname == NULL) {
666 network_config_check_interface_settings(NULL);
667 return;
668 }
669 if_list = xpc_array_create(NULL, 0);
670 xpc_array_set_string(if_list, XPC_ARRAY_APPEND, ifname);
671 network_config_check_interface_settings(if_list);
672 xpc_release(if_list);
673 return;
674 }
675
676 static void
677 update_interfaces(const char * msg, Boolean first_time)
678 {
679 Boolean added = FALSE;
680 struct ifaddrs * ifap = NULL;
681 CFMutableArrayRef ifList = NULL;
682 struct ifaddrs * scan;
683
684 if (getifaddrs(&ifap) == -1) {
685 messages_add_msg_with_arg("getifaddrs", strerror(errno));
686 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
687 goto done;
688 }
689
690 /* update list of interfaces & link status */
691 ifList = interfaceListCopy();
692 for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
693 if (scan->ifa_addr == NULL
694 || scan->ifa_addr->sa_family != AF_LINK) {
695 continue;
696 }
697 /* get the per-interface link/media information */
698 if (interfaceListAddInterface(ifList, scan->ifa_name)) {
699 messages_add_msg_with_arg(msg, scan->ifa_name);
700 added = TRUE;
701 if (!first_time) {
702 config_new_interface(scan->ifa_name);
703 }
704 }
705 }
706
707 /* update the global list if an interface was added */
708 if (added) {
709 interfaceListUpdate(ifList);
710 }
711 CFRelease(ifList);
712
713 /* update IPv4/IPv6 addresses that are already assigned */
714 if (first_time) {
715 ipv4_interface_update(ifap, NULL);
716 interface_update_ipv6(ifap, NULL);
717 }
718
719 freeifaddrs(ifap);
720
721 done:
722 if (first_time) {
723 /* tell networkd to get the interface list itself */
724 config_new_interface(NULL);
725 }
726 return;
727 }
728
729 #define TIMER_INTERVAL (6LL * NSEC_PER_SEC)
730 #define MAX_TIMER_COUNT 20
731
732 static void
733 check_for_new_interfaces(void * context);
734
735 static void
736 schedule_timer(void)
737 {
738 dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, TIMER_INTERVAL),
739 S_kev_queue,
740 NULL,
741 check_for_new_interfaces);
742 return;
743 }
744
745 static void
746 check_for_new_interfaces(void * context)
747 {
748 #pragma unused(context)
749 static int count;
750 char msg[32];
751
752 count++;
753
754 /* update KEV driven content in case a message got dropped */
755 snprintf(msg, sizeof(msg), "update %d (of %d)", count, MAX_TIMER_COUNT);
756 _SCDynamicStoreCacheOpen(store);
757 update_interfaces(msg, FALSE);
758 _SCDynamicStoreCacheCommitChanges(store);
759 _SCDynamicStoreCacheClose(store);
760 messages_post();
761
762 /* schedule the next timer, if needed */
763 if (count < MAX_TIMER_COUNT) {
764 schedule_timer();
765 }
766 else {
767 messages_free();
768 }
769
770 return;
771 }
772
773 static void
774 prime(void)
775 {
776 SC_log(LOG_DEBUG, "prime() called");
777
778 _SCDynamicStoreCacheOpen(store);
779 messages_init();
780 update_interfaces("prime", TRUE);
781 _SCDynamicStoreCacheCommitChanges(store);
782 _SCDynamicStoreCacheClose(store);
783
784 network_changed = TRUE;
785 post_network_changed();
786 messages_post();
787
788 /* start handling kernel events */
789 dispatch_resume(S_kev_source);
790
791 /* schedule polling timer */
792 schedule_timer();
793
794 return;
795 }
796
797
798 __private_extern__
799 void
800 prime_KernelEventMonitor()
801 {
802 dispatch_async(S_kev_queue, ^{ prime(); });
803 return;
804 }
805
806 static Boolean
807 initialize_store(void)
808 {
809 store = SCDynamicStoreCreate(NULL,
810 CFSTR("Kernel Event Monitor plug-in"),
811 NULL,
812 NULL);
813 if (store == NULL) {
814 SC_log(LOG_ERR, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
815 return (FALSE);
816 }
817 return (TRUE);
818 }
819
820
821 __private_extern__
822 void
823 load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
824 {
825 struct kev_request kev_req;
826 int so;
827 int status;
828
829 if (bundleVerbose) {
830 _verbose = TRUE;
831 }
832
833 SC_log(LOG_DEBUG, "load() called");
834 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
835
836 if (!initialize_store()) {
837 SC_log(LOG_ERR, "kernel event monitor disabled");
838 return;
839 }
840
841 /* Open an event socket */
842 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
843 if (so != -1) {
844 /* establish filter to return events of interest */
845 kev_req.vendor_code = KEV_VENDOR_APPLE;
846 kev_req.kev_class = KEV_NETWORK_CLASS;
847 kev_req.kev_subclass = KEV_ANY_SUBCLASS;
848 status = ioctl(so, SIOCSKEVFILT, &kev_req);
849 if (status != 0) {
850 SC_log(LOG_ERR, "could not establish event filter, ioctl() failed: %s", strerror(errno));
851 (void) close(so);
852 so = -1;
853 }
854 } else {
855 SC_log(LOG_ERR, "could not open event socket, socket() failed: %s", strerror(errno));
856 }
857
858 if (so != -1) {
859 int yes = 1;
860
861 status = ioctl(so, FIONBIO, &yes);
862 if (status) {
863 SC_log(LOG_ERR, "could not set non-blocking io, ioctl() failed: %s", strerror(errno));
864 (void) close(so);
865 so = -1;
866 }
867 }
868
869 if (so == -1) {
870 SC_log(LOG_ERR, "kernel event monitor disabled");
871 CFRelease(store);
872 return;
873 }
874
875 S_kev_queue = dispatch_queue_create("com.apple.SystemConfiguration.KernelEventMonitor", NULL);
876 S_kev_source
877 = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, so, 0, S_kev_queue);
878 dispatch_source_set_cancel_handler(S_kev_source, ^{
879 close(so);
880 });
881 dispatch_source_set_event_handler(S_kev_source, ^{
882 Boolean ok;
883
884 ok = eventCallback(so);
885 if (!ok) {
886 SC_log(LOG_ERR, "kernel event monitor disabled");
887 dispatch_source_cancel(S_kev_source);
888 }
889 });
890 // NOTE: dispatch_resume() will be called in prime()
891
892 return;
893 }
894
895 #ifdef MAIN
896
897 #include "ev_dlil.c"
898
899 #define appendAddress appendAddress_v4
900 #define getIF getIF_v4
901 #define updateStore updateStore_v4
902 #include "ev_ipv4.c"
903 #undef appendAddress
904 #undef getIF
905 #undef updateStore
906
907 #define appendAddress appendAddress_v6
908 #define getIF getIF_v6
909 #define updateStore updateStore_v6
910 #include "ev_ipv6.c"
911 #undef appendAddress
912 #undef getIF
913 #undef updateStore
914
915 int
916 main(int argc, char **argv)
917 {
918 _sc_log = kSCLogDestinationFile;
919 _sc_verbose = (argc > 1) ? TRUE : FALSE;
920
921 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
922 prime_KernelEventMonitor();
923 dispatch_main();
924 /* not reached */
925 exit(0);
926 return 0;
927 }
928 #endif