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