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