]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/eventmon.c
configd-888.51.2.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
1 /*
2 * Copyright (c) 2000-2016 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 "cache.h"
58 #include "ev_dlil.h"
59 #include "ev_ipv4.h"
60 #include "ev_ipv6.h"
61 #include <notify.h>
62 #include <sys/sysctl.h>
63 #include <sys/kern_event.h>
64 #include <network/config.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()
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 int
182 ifflags_set(int s, char * name, short flags)
183 {
184 struct ifreq ifr;
185 int ret;
186
187 bzero(&ifr, sizeof(ifr));
188 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
189 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
190 if (ret == -1) {
191 return (ret);
192 }
193 ifr.ifr_flags |= flags;
194 return (ioctl(s, SIOCSIFFLAGS, &ifr));
195 }
196
197 static int
198 ifflags_clear(int s, char * name, short flags)
199 {
200 struct ifreq ifr;
201 int ret;
202
203 bzero(&ifr, sizeof(ifr));
204 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
205 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
206 if (ret == -1) {
207 return (ret);
208 }
209 ifr.ifr_flags &= ~flags;
210 return (ioctl(s, SIOCSIFFLAGS, &ifr));
211 }
212
213 static void
214 mark_if_up(char * name)
215 {
216 int s = dgram_socket(AF_INET);
217 if (s == -1)
218 return;
219 ifflags_set(s, name, IFF_UP);
220 close(s);
221 }
222
223 static void
224 mark_if_down(char * name)
225 {
226 int s = dgram_socket(AF_INET);
227 if (s == -1)
228 return;
229 ifflags_clear(s, name, IFF_UP);
230 close(s);
231 }
232
233 static void
234 post_network_changed(void)
235 {
236 if (network_changed) {
237 uint32_t status;
238
239 status = notify_post(_SC_NOTIFY_NETWORK_CHANGE);
240 if (status != NOTIFY_STATUS_OK) {
241 SC_log(LOG_NOTICE, "notify_post() failed: error=%u", status);
242 }
243
244 network_changed = FALSE;
245 }
246
247 return;
248 }
249
250 static void
251 logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
252 {
253 int i;
254 int j;
255
256 if (!_verbose) {
257 return;
258 }
259
260 SC_log(LOG_DEBUG, "%@ event:", evStr);
261 SC_log(LOG_DEBUG, " Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d",
262 ev_msg->total_size,
263 ev_msg->id,
264 ev_msg->vendor_code,
265 ev_msg->kev_class,
266 ev_msg->kev_subclass,
267 ev_msg->event_code);
268 for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
269 SC_log(LOG_DEBUG, " Event data[%2d] = %08x", i, ev_msg->event_data[i]);
270 }
271 }
272
273 static void
274 copy_if_name(const struct net_event_data * ev, char * ifr_name, int ifr_len)
275 {
276 snprintf(ifr_name, ifr_len, "%s%d", ev->if_name, ev->if_unit);
277 return;
278 }
279
280 static uint8_t info_zero[DLIL_MODARGLEN];
281
282 static void
283 processEvent_Apple_Network(struct kern_event_msg *ev_msg)
284 {
285 int dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
286 void * event_data = &ev_msg->event_data[0];
287 Boolean handled = TRUE;
288 char ifr_name[IFNAMSIZ];
289
290 switch (ev_msg->kev_subclass) {
291 case KEV_INET_SUBCLASS : {
292 switch (ev_msg->event_code) {
293 case KEV_INET_NEW_ADDR :
294 case KEV_INET_CHANGED_ADDR :
295 case KEV_INET_ADDR_DELETED :
296 case KEV_INET_SIFDSTADDR :
297 case KEV_INET_SIFBRDADDR :
298 case KEV_INET_SIFNETMASK : {
299 struct kev_in_data * ev;
300
301 ev = (struct kev_in_data *)event_data;
302 if (dataLen < sizeof(*ev)) {
303 handled = FALSE;
304 break;
305 }
306 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
307 SC_log(LOG_INFO, "Process IPv4 address change: %s: %d", (char *)ifr_name, ev_msg->event_code);
308 ipv4_interface_update(NULL, ifr_name);
309 if (ev_msg->event_code
310 != KEV_INET_ADDR_DELETED) {
311 check_interface_link_status(ifr_name);
312 }
313 break;
314 }
315 case KEV_INET_ARPCOLLISION : {
316 struct kev_in_collision * ev;
317
318 ev = (struct kev_in_collision *)event_data;
319 if ((dataLen < sizeof(*ev))
320 || (dataLen < (sizeof(*ev) + ev->hw_len))) {
321 handled = FALSE;
322 break;
323 }
324 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
325 SC_log(LOG_INFO, "Process ARP collision: %s", (char *)ifr_name);
326 ipv4_arp_collision(ifr_name,
327 ev->ia_ipaddr,
328 ev->hw_len,
329 ev->hw_addr);
330 break;
331 }
332 #if !TARGET_OS_IPHONE
333 case KEV_INET_PORTINUSE : {
334 struct kev_in_portinuse * ev;
335 ev = (struct kev_in_portinuse *)event_data;
336 if (dataLen < sizeof(*ev)) {
337 handled = FALSE;
338 break;
339 }
340 SC_log(LOG_INFO, "Process port-in-use: %hu, %u", ev->port, ev->req_pid);
341 ipv4_port_in_use(ev->port, ev->req_pid);
342 break;
343 }
344 #endif /* !TARGET_OS_IPHONE */
345 case KEV_INET_ARPRTRFAILURE: {
346 const struct kev_in_arpfailure * ev;
347
348 ev = (const struct kev_in_arpfailure *)event_data;
349 if (dataLen < sizeof(*ev)) {
350 handled = FALSE;
351 break;
352 }
353 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
354 SC_log(LOG_INFO, "Process router ARP failure: %s", (char *)ifr_name);
355 ipv4_router_arp_failure(ifr_name);
356 break;
357 }
358 case KEV_INET_ARPRTRALIVE: {
359 const struct kev_in_arpalive * ev;
360
361 ev = (const struct kev_in_arpalive *)event_data;
362 if (dataLen < sizeof(*ev)) {
363 handled = FALSE;
364 break;
365 }
366 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
367 SC_log(LOG_INFO, "Process router ARP alive: %s", (char *)ifr_name);
368 ipv4_router_arp_alive(ifr_name);
369 break;
370 }
371 default :
372 break;
373 }
374 break;
375 }
376
377 case KEV_INET6_SUBCLASS : {
378 struct kev_in6_data * ev;
379
380 ev = (struct kev_in6_data *)event_data;
381 switch (ev_msg->event_code) {
382 case KEV_INET6_NEW_USER_ADDR :
383 case KEV_INET6_CHANGED_ADDR :
384 case KEV_INET6_ADDR_DELETED :
385 case KEV_INET6_NEW_LL_ADDR :
386 case KEV_INET6_NEW_RTADV_ADDR :
387 case KEV_INET6_DEFROUTER :
388 if (dataLen < sizeof(*ev)) {
389 handled = FALSE;
390 break;
391 }
392 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
393 SC_log(LOG_INFO, "Process IPv6 address change: %s: %d", (char *)ifr_name, ev_msg->event_code);
394 interface_update_ipv6(NULL, ifr_name);
395 if (ev_msg->event_code == KEV_INET6_NEW_USER_ADDR
396 && (ev->ia6_flags & IN6_IFF_DUPLICATED) != 0) {
397 ipv6_duplicated_address(ifr_name,
398 &ev->ia_addr.sin6_addr,
399 ETHER_ADDR_LEN,
400 &ev->ia_mac);
401 }
402 if (ev_msg->event_code
403 != KEV_INET6_ADDR_DELETED) {
404 check_interface_link_status(ifr_name);
405 }
406 break;
407
408 default :
409 break;
410 }
411 break;
412 }
413
414 case KEV_DL_SUBCLASS : {
415 struct net_event_data * ev;
416
417 ev = (struct net_event_data *)event_data;
418 switch (ev_msg->event_code) {
419 case KEV_DL_IF_ATTACHED :
420 /*
421 * new interface added
422 */
423 if (dataLen < sizeof(*ev)) {
424 handled = FALSE;
425 break;
426 }
427 copy_if_name(ev, ifr_name, sizeof(ifr_name));
428 SC_log(LOG_INFO, "Process interface attach: %s", (char *)ifr_name);
429 link_add(ifr_name);
430 break;
431
432 case KEV_DL_IF_DETACHED :
433 /*
434 * interface removed
435 */
436 if (dataLen < sizeof(*ev)) {
437 handled = FALSE;
438 break;
439 }
440 copy_if_name(ev, ifr_name, sizeof(ifr_name));
441 SC_log(LOG_INFO, "Process interface detach: %s", (char *)ifr_name);
442 link_remove(ifr_name);
443 break;
444
445 case KEV_DL_IF_DETACHING :
446 /*
447 * interface detaching
448 */
449 if (dataLen < sizeof(*ev)) {
450 handled = FALSE;
451 break;
452 }
453 copy_if_name(ev, ifr_name, sizeof(ifr_name));
454 SC_log(LOG_INFO, "Process interface detaching: %s", (char *)ifr_name);
455 interface_detaching(ifr_name);
456 break;
457
458 case KEV_DL_PROTO_ATTACHED :
459 case KEV_DL_PROTO_DETACHED : {
460 struct kev_dl_proto_data * protoEvent;
461
462 protoEvent = (struct kev_dl_proto_data *)event_data;
463 if (dataLen < sizeof(*protoEvent)) {
464 handled = FALSE;
465 break;
466 }
467 copy_if_name(&protoEvent->link_data,
468 ifr_name, sizeof(ifr_name));
469 SC_log(LOG_INFO, "Process protocol %s: %s (n=%d)",
470 (ev_msg->event_code == KEV_DL_PROTO_ATTACHED) ? "attach" : "detach",
471 (char *)ifr_name,
472 protoEvent->proto_remaining_count);
473 if (protoEvent->proto_remaining_count == 0) {
474 mark_if_down(ifr_name);
475 } else {
476 mark_if_up(ifr_name);
477 }
478 break;
479 }
480
481 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
482 case KEV_DL_IF_IDLE_ROUTE_REFCNT: {
483 /*
484 * interface route refcnt idle
485 */
486 if (dataLen < sizeof(*ev)) {
487 handled = FALSE;
488 break;
489 }
490 copy_if_name(ev, ifr_name, sizeof(ifr_name));
491 SC_log(LOG_INFO, "Process interface idle: %s", (char *)ifr_name);
492 interface_update_idle_state(ifr_name);
493 break;
494 }
495 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
496
497 case KEV_DL_LINK_OFF :
498 case KEV_DL_LINK_ON :
499 /*
500 * update the link status in the store
501 */
502 if (dataLen < sizeof(*ev)) {
503 handled = FALSE;
504 break;
505 }
506 copy_if_name(ev, ifr_name, sizeof(ifr_name));
507 SC_log(LOG_INFO, "Process interface link %s: %s",
508 (ev_msg->event_code == KEV_DL_LINK_ON) ? "up" : "down",
509 (char *)ifr_name);
510 link_update_status(ifr_name, FALSE, FALSE);
511 break;
512
513 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
514 case KEV_DL_LINK_QUALITY_METRIC_CHANGED: {
515 struct kev_dl_link_quality_metric_data * lqm_data;
516 lqm_data = (struct kev_dl_link_quality_metric_data *) event_data;
517
518 if (dataLen < sizeof(*ev)) {
519 handled = FALSE;
520 break;
521 }
522 copy_if_name(ev, ifr_name, sizeof(ifr_name));
523 SC_log(LOG_INFO, "Process interface quality: %s (q=%d)",
524 (char *)ifr_name,
525 lqm_data->link_quality_metric);
526 interface_update_quality_metric(ifr_name,
527 lqm_data->link_quality_metric);
528 break;
529 }
530 #endif // KEV_DL_LINK_QUALITY_METRIC_CHANGED
531
532 #ifdef KEV_DL_ISSUES
533 case KEV_DL_ISSUES: {
534 struct kev_dl_issues *issues;
535
536 issues = (struct kev_dl_issues *)event_data;
537 if (dataLen < sizeof(*ev)) {
538 handled = FALSE;
539 break;
540 }
541 copy_if_name(ev, ifr_name, sizeof(ifr_name));
542 SC_log(LOG_INFO, "Process interface link issues: %s",
543 (char *)ifr_name);
544 interface_update_link_issues(ifr_name,
545 issues->timestamp,
546 issues->modid,
547 DLIL_MODIDLEN,
548 issues->info,
549 (bcmp(issues->info, info_zero, DLIL_MODARGLEN) != 0)
550 ? DLIL_MODARGLEN
551 : 0);
552 break;
553 }
554 #endif // KEV_DL_ISSUES
555
556 default :
557 break;
558 }
559 break;
560 }
561
562 #ifdef KEV_NETPOLICY_SUBCLASS
563 case KEV_NETPOLICY_SUBCLASS : {
564 break;
565 }
566 #endif // KEV_NETPOLICY_SUBCLASS
567
568 #ifdef KEV_SOCKET_SUBCLASS
569 case KEV_SOCKET_SUBCLASS : {
570 break;
571 }
572 #endif // KEV_SOCKET_SUBCLASS
573
574 #ifdef KEV_ND6_SUBCLASS
575 case KEV_ND6_SUBCLASS : {
576 break;
577 }
578 #endif // KEV_ND6_SUBCLASS
579
580 #ifdef KEV_NECP_SUBCLASS
581 case KEV_NECP_SUBCLASS : {
582 break;
583 }
584 #endif // KEV_NECP_SUBCLASS
585
586 #ifdef KEV_NETAGENT_SUBCLASS
587 case KEV_NETAGENT_SUBCLASS : {
588 break;
589 }
590 #endif // KEV_NETAGENT_SUBCLASS
591
592 #ifdef KEV_LOG_SUBCLASS
593 case KEV_LOG_SUBCLASS : {
594 break;
595 }
596 #endif // KEV_LOG_SUBCLASS
597
598 #ifdef KEV_NETEVENT_SUBCLASS
599 case KEV_NETEVENT_SUBCLASS : {
600 break;
601 }
602 #endif // KEV_NETEVENT_SUBCLASS
603
604 default :
605 break;
606 }
607
608 if (!handled) {
609 logEvent(CFSTR("Error processing (Apple network subclass)"), ev_msg);
610 }
611 return;
612 }
613
614 static Boolean
615 eventCallback(int so)
616 {
617 ssize_t status;
618 union {
619 char bytes[1024];
620 struct kern_event_msg ev_msg1; // first kernel event
621 } buf;
622 struct kern_event_msg *ev_msg = &buf.ev_msg1;
623 ssize_t offset = 0;
624
625 status = recv(so, &buf, sizeof(buf), 0);
626 if (status == -1) {
627 SC_log(LOG_NOTICE, "recv() failed: %s", strerror(errno));
628 return FALSE;
629 }
630
631 cache_open();
632
633 while (offset < status) {
634 if ((offset + ev_msg->total_size) > status) {
635 SC_log(LOG_NOTICE, "missed SYSPROTO_EVENT event, buffer not big enough");
636 break;
637 }
638
639 switch (ev_msg->vendor_code) {
640 case KEV_VENDOR_APPLE :
641 switch (ev_msg->kev_class) {
642 case KEV_NETWORK_CLASS :
643 processEvent_Apple_Network(ev_msg);
644 break;
645
646 default :
647 break;
648 }
649 break;
650 default :
651 break;
652 }
653 offset += ev_msg->total_size;
654 ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset];
655 }
656
657 cache_write(store);
658 cache_close();
659 post_network_changed();
660 messages_post();
661
662 return TRUE;
663 }
664
665
666 __private_extern__ void
667 config_new_interface(const char * ifname)
668 {
669 xpc_object_t if_list;
670
671 if (ifname == NULL) {
672 network_config_check_interface_settings(NULL);
673 return;
674 }
675 if_list = xpc_array_create(NULL, 0);
676 xpc_array_set_string(if_list, XPC_ARRAY_APPEND, ifname);
677 network_config_check_interface_settings(if_list);
678 xpc_release(if_list);
679 return;
680 }
681
682 static void
683 update_interfaces(const char * msg, Boolean first_time)
684 {
685 Boolean added = FALSE;
686 struct ifaddrs * ifap = NULL;
687 CFMutableArrayRef ifList = NULL;
688 struct ifaddrs * scan;
689
690 if (getifaddrs(&ifap) == -1) {
691 messages_add_msg_with_arg("getifaddrs", strerror(errno));
692 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
693 goto done;
694 }
695
696 /* update list of interfaces & link status */
697 ifList = interfaceListCopy();
698 for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
699 if (scan->ifa_addr == NULL
700 || scan->ifa_addr->sa_family != AF_LINK) {
701 continue;
702 }
703 /* get the per-interface link/media information */
704 if (interfaceListAddInterface(ifList, scan->ifa_name)) {
705 messages_add_msg_with_arg(msg, scan->ifa_name);
706 added = TRUE;
707 if (!first_time) {
708 config_new_interface(scan->ifa_name);
709 }
710 }
711 }
712
713 /* update the global list if an interface was added */
714 if (added) {
715 interfaceListUpdate(ifList);
716 }
717 CFRelease(ifList);
718
719 /* update IPv4/IPv6 addresses that are already assigned */
720 if (first_time) {
721 ipv4_interface_update(ifap, NULL);
722 interface_update_ipv6(ifap, NULL);
723 }
724
725 freeifaddrs(ifap);
726
727 done:
728 if (first_time) {
729 /* tell networkd to get the interface list itself */
730 config_new_interface(NULL);
731 }
732 return;
733 }
734
735 #define TIMER_INTERVAL (6LL * NSEC_PER_SEC)
736 #define MAX_TIMER_COUNT 20
737
738 static void
739 check_for_new_interfaces(void * context);
740
741 static void
742 schedule_timer(void)
743 {
744 dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, TIMER_INTERVAL),
745 S_kev_queue,
746 NULL,
747 check_for_new_interfaces);
748 return;
749 }
750
751 static void
752 check_for_new_interfaces(void * context)
753 {
754 static int count;
755 char msg[32];
756
757 count++;
758
759 /* update KEV driven content in case a message got dropped */
760 snprintf(msg, sizeof(msg), "update %d (of %d)", count, MAX_TIMER_COUNT);
761 cache_open();
762 update_interfaces(msg, FALSE);
763 cache_write(store);
764 cache_close();
765 messages_post();
766
767 /* schedule the next timer, if needed */
768 if (count < MAX_TIMER_COUNT) {
769 schedule_timer();
770 }
771 else {
772 messages_free();
773 }
774
775 return;
776 }
777
778 static void
779 prime(void)
780 {
781 SC_log(LOG_DEBUG, "prime() called");
782
783 cache_open();
784 messages_init();
785 update_interfaces("prime", TRUE);
786 cache_write(store);
787 cache_close();
788
789 network_changed = TRUE;
790 post_network_changed();
791 messages_post();
792
793 /* start handling kernel events */
794 dispatch_resume(S_kev_source);
795
796 /* schedule polling timer */
797 schedule_timer();
798
799 return;
800 }
801
802
803 __private_extern__
804 void
805 prime_KernelEventMonitor()
806 {
807 dispatch_async(S_kev_queue, ^{ prime(); });
808 return;
809 }
810
811 static Boolean
812 initialize_store(void)
813 {
814 store = SCDynamicStoreCreate(NULL,
815 CFSTR("Kernel Event Monitor plug-in"),
816 NULL,
817 NULL);
818 if (store == NULL) {
819 SC_log(LOG_ERR, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
820 return (FALSE);
821 }
822 return (TRUE);
823 }
824
825
826 __private_extern__
827 void
828 load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
829 {
830 struct kev_request kev_req;
831 int so;
832 int status;
833
834 if (bundleVerbose) {
835 _verbose = TRUE;
836 }
837
838 SC_log(LOG_DEBUG, "load() called");
839 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
840
841 if (!initialize_store()) {
842 SC_log(LOG_ERR, "kernel event monitor disabled");
843 return;
844 }
845
846 /* Open an event socket */
847 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
848 if (so != -1) {
849 /* establish filter to return events of interest */
850 kev_req.vendor_code = KEV_VENDOR_APPLE;
851 kev_req.kev_class = KEV_NETWORK_CLASS;
852 kev_req.kev_subclass = KEV_ANY_SUBCLASS;
853 status = ioctl(so, SIOCSKEVFILT, &kev_req);
854 if (status != 0) {
855 SC_log(LOG_ERR, "could not establish event filter, ioctl() failed: %s", strerror(errno));
856 (void) close(so);
857 so = -1;
858 }
859 } else {
860 SC_log(LOG_ERR, "could not open event socket, socket() failed: %s", strerror(errno));
861 }
862
863 if (so != -1) {
864 int yes = 1;
865
866 status = ioctl(so, FIONBIO, &yes);
867 if (status) {
868 SC_log(LOG_ERR, "could not set non-blocking io, ioctl() failed: %s", strerror(errno));
869 (void) close(so);
870 so = -1;
871 }
872 }
873
874 if (so == -1) {
875 SC_log(LOG_ERR, "kernel event monitor disabled");
876 CFRelease(store);
877 return;
878 }
879
880 S_kev_queue = dispatch_queue_create("com.apple.SystemConfiguration.KernelEventMonitor", NULL);
881 S_kev_source
882 = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, so, 0, S_kev_queue);
883 dispatch_source_set_cancel_handler(S_kev_source, ^{
884 close(so);
885 });
886 dispatch_source_set_event_handler(S_kev_source, ^{
887 os_activity_t activity;
888 Boolean ok;
889
890 activity = os_activity_create("processing network kernel events",
891 OS_ACTIVITY_CURRENT,
892 OS_ACTIVITY_FLAG_DEFAULT);
893 os_activity_scope(activity);
894
895 ok = eventCallback(so);
896 if (!ok) {
897 SC_log(LOG_ERR, "kernel event monitor disabled");
898 dispatch_source_cancel(S_kev_source);
899 }
900
901 os_release(activity);
902 });
903 // NOTE: dispatch_resume() will be called in prime()
904
905 return;
906 }
907
908 #ifdef MAIN
909
910 #include "ev_dlil.c"
911
912 #define appendAddress appendAddress_v4
913 #define getIF getIF_v4
914 #define updateStore updateStore_v4
915 #include "ev_ipv4.c"
916 #undef appendAddress
917 #undef getIF
918 #undef updateStore
919
920 #define appendAddress appendAddress_v6
921 #define getIF getIF_v6
922 #define updateStore updateStore_v6
923 #include "ev_ipv6.c"
924 #undef appendAddress
925 #undef getIF
926 #undef updateStore
927
928 int
929 main(int argc, char **argv)
930 {
931 _sc_log = FALSE;
932 _sc_verbose = (argc > 1) ? TRUE : FALSE;
933
934 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
935 prime_KernelEventMonitor();
936 dispatch_main();
937 /* not reached */
938 exit(0);
939 return 0;
940 }
941 #endif