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