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