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