]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/eventmon.c
configd-453.18.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
1 /*
2 * Copyright (c) 2000-2008, 2010, 2011 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 const char *inetEventName[] = {
67 "",
68 "INET address added",
69 "INET address changed",
70 "INET address deleted",
71 "INET destination address changed",
72 "INET broadcast address changed",
73 "INET netmask changed",
74 "INET ARP collision",
75 "INET port in use",
76 };
77
78 static const char *dlEventName[] = {
79 "",
80 "KEV_DL_SIFFLAGS",
81 "KEV_DL_SIFMETRICS",
82 "KEV_DL_SIFMTU",
83 "KEV_DL_SIFPHYS",
84 "KEV_DL_SIFMEDIA",
85 "KEV_DL_SIFGENERIC",
86 "KEV_DL_ADDMULTI",
87 "KEV_DL_DELMULTI",
88 "KEV_DL_IF_ATTACHED",
89 "KEV_DL_IF_DETACHING",
90 "KEV_DL_IF_DETACHED",
91 "KEV_DL_LINK_OFF",
92 "KEV_DL_LINK_ON",
93 "KEV_DL_PROTO_ATTACHED",
94 "KEV_DL_PROTO_DETACHED",
95 "KEV_DL_LINK_ADDRESS_CHANGED",
96 "KEV_DL_WAKEFLAGS_CHANGED",
97 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
98 "KEV_DL_IF_IDLE_ROUTE_REFCNT",
99 #endif
100 #ifdef KEV_DL_IFCAP_CHANGED
101 "KEV_DL_IFCAP_CHANGED",
102 #endif
103 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
104 "KEV_DL_LINK_QUALITY_METRIC_CHANGED",
105 #endif
106 };
107
108 static const char *inet6EventName[] = {
109 "",
110 "KEV_INET6_NEW_USER_ADDR",
111 "KEV_INET6_CHANGED_ADDR",
112 "KEV_INET6_ADDR_DELETED",
113 "KEV_INET6_NEW_LL_ADDR",
114 "KEV_INET6_NEW_RTADV_ADDR",
115 "KEV_INET6_DEFROUTER"
116 };
117
118 #ifdef KEV_ND6_SUBCLASS
119 static const char *nd6EventNameString[] = {
120 "",
121 "KEV_ND6_RA"
122 };
123 #endif // KEV_ND6_SUBCLASS
124
125 __private_extern__ Boolean network_changed = FALSE;
126 __private_extern__ SCDynamicStoreRef store = NULL;
127 __private_extern__ Boolean _verbose = FALSE;
128
129 __private_extern__
130 int
131 dgram_socket(int domain)
132 {
133 return (socket(domain, SOCK_DGRAM, 0));
134 }
135
136 static int
137 ifflags_set(int s, char * name, short flags)
138 {
139 struct ifreq ifr;
140 int ret;
141
142 bzero(&ifr, sizeof(ifr));
143 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
144 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
145 if (ret == -1) {
146 return (ret);
147 }
148 ifr.ifr_flags |= flags;
149 return (ioctl(s, SIOCSIFFLAGS, &ifr));
150 }
151
152 static int
153 ifflags_clear(int s, char * name, short flags)
154 {
155 struct ifreq ifr;
156 int ret;
157
158 bzero(&ifr, sizeof(ifr));
159 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
160 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
161 if (ret == -1) {
162 return (ret);
163 }
164 ifr.ifr_flags &= ~flags;
165 return (ioctl(s, SIOCSIFFLAGS, &ifr));
166 }
167
168 static void
169 mark_if_up(char * name)
170 {
171 int s = dgram_socket(AF_INET);
172 if (s == -1)
173 return;
174 ifflags_set(s, name, IFF_UP);
175 close(s);
176 }
177
178 static void
179 mark_if_down(char * name)
180 {
181 int s = dgram_socket(AF_INET);
182 if (s == -1)
183 return;
184 ifflags_clear(s, name, IFF_UP);
185 close(s);
186 }
187
188 static void
189 post_network_changed(void)
190 {
191 if (network_changed) {
192 uint32_t status;
193
194 status = notify_post("com.apple.system.config.network_change");
195 if (status != NOTIFY_STATUS_OK) {
196 SCLog(TRUE, LOG_ERR, CFSTR("notify_post() failed: error=%ld"), status);
197 }
198
199 network_changed = FALSE;
200 }
201
202 return;
203 }
204
205 static void
206 logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
207 {
208 int i;
209 int j;
210
211 if (!_verbose) {
212 return;
213 }
214
215 SCLog(TRUE, LOG_DEBUG, CFSTR("%@ event:"), evStr);
216 SCLog(TRUE, LOG_DEBUG,
217 CFSTR(" Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d"),
218 ev_msg->total_size,
219 ev_msg->id,
220 ev_msg->vendor_code,
221 ev_msg->kev_class,
222 ev_msg->kev_subclass,
223 ev_msg->event_code);
224 for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
225 SCLog(TRUE, LOG_DEBUG, CFSTR(" Event data[%2d] = %08lx"), i, ev_msg->event_data[i]);
226 }
227 }
228
229 static const char *
230 inetEventNameString(uint32_t event_code)
231 {
232 if (event_code < sizeof(inetEventName) / sizeof(inetEventName[0])) {
233 return (inetEventName[event_code]);
234 }
235 return ("New Apple network INET subcode");
236 }
237
238 static const char *
239 inet6EventNameString(uint32_t event_code)
240 {
241 if (event_code < sizeof(inet6EventName) / sizeof(inet6EventName[0])) {
242 return (inet6EventName[event_code]);
243 }
244 return ("New Apple network INET6 subcode");
245 }
246
247 static const char *
248 dlEventNameString(uint32_t event_code)
249 {
250 if (event_code < sizeof(dlEventName) / sizeof(dlEventName[0])) {
251 return (dlEventName[event_code]);
252 }
253 return ("New Apple network DL subcode");
254 }
255
256 static void
257 copy_if_name(struct net_event_data * ev, char * ifr_name, int ifr_len)
258 {
259 snprintf(ifr_name, ifr_len, "%s%d", ev->if_name, ev->if_unit);
260 return;
261 }
262
263 static void
264 processEvent_Apple_Network(struct kern_event_msg *ev_msg)
265 {
266 const char * eventName = NULL;
267 int dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
268 void * event_data = &ev_msg->event_data[0];
269 Boolean handled = TRUE;
270 char ifr_name[IFNAMSIZ];
271
272 switch (ev_msg->kev_subclass) {
273 case KEV_INET_SUBCLASS : {
274 eventName = inetEventNameString(ev_msg->event_code);
275 switch (ev_msg->event_code) {
276 case KEV_INET_NEW_ADDR :
277 case KEV_INET_CHANGED_ADDR :
278 case KEV_INET_ADDR_DELETED :
279 case KEV_INET_SIFDSTADDR :
280 case KEV_INET_SIFBRDADDR :
281 case KEV_INET_SIFNETMASK : {
282 struct kev_in_data * ev;
283
284 ev = (struct kev_in_data *)event_data;
285 if (dataLen < sizeof(*ev)) {
286 handled = FALSE;
287 break;
288 }
289 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
290 interface_update_ipv4(NULL, ifr_name);
291 break;
292 }
293 case KEV_INET_ARPCOLLISION : {
294 struct kev_in_collision * ev;
295
296 ev = (struct kev_in_collision *)event_data;
297 if ((dataLen < sizeof(*ev))
298 || (dataLen < (sizeof(*ev) + ev->hw_len))) {
299 handled = FALSE;
300 break;
301 }
302 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
303 interface_collision_ipv4(ifr_name,
304 ev->ia_ipaddr,
305 ev->hw_len,
306 ev->hw_addr);
307 break;
308 }
309 #if !TARGET_OS_IPHONE
310 case KEV_INET_PORTINUSE : {
311 struct kev_in_portinuse * ev;
312 ev = (struct kev_in_portinuse *)event_data;
313 if (dataLen < sizeof(*ev)) {
314 handled = FALSE;
315 break;
316 }
317 port_in_use_ipv4(ev->port, ev->req_pid);
318 break;
319 }
320 #endif /* !TARGET_OS_IPHONE */
321 default :
322 handled = FALSE;
323 break;
324 }
325 break;
326 }
327 case KEV_INET6_SUBCLASS : {
328 struct kev_in6_data * ev;
329
330 eventName = inet6EventNameString(ev_msg->event_code);
331 ev = (struct kev_in6_data *)event_data;
332 switch (ev_msg->event_code) {
333 case KEV_INET6_NEW_USER_ADDR :
334 case KEV_INET6_CHANGED_ADDR :
335 case KEV_INET6_ADDR_DELETED :
336 case KEV_INET6_NEW_LL_ADDR :
337 case KEV_INET6_NEW_RTADV_ADDR :
338 case KEV_INET6_DEFROUTER :
339 if (dataLen < sizeof(*ev)) {
340 handled = FALSE;
341 break;
342 }
343 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
344 interface_update_ipv6(NULL, ifr_name);
345 break;
346
347 default :
348 handled = FALSE;
349 break;
350 }
351 break;
352 }
353 case KEV_DL_SUBCLASS : {
354 struct net_event_data * ev;
355
356 eventName = dlEventNameString(ev_msg->event_code);
357 ev = (struct net_event_data *)event_data;
358 switch (ev_msg->event_code) {
359 case KEV_DL_IF_ATTACHED :
360 /*
361 * new interface added
362 */
363 if (dataLen < sizeof(*ev)) {
364 handled = FALSE;
365 break;
366 }
367 copy_if_name(ev, ifr_name, sizeof(ifr_name));
368 link_add(ifr_name);
369 break;
370
371 case KEV_DL_IF_DETACHED :
372 /*
373 * interface removed
374 */
375 if (dataLen < sizeof(*ev)) {
376 handled = FALSE;
377 break;
378 }
379 copy_if_name(ev, ifr_name, sizeof(ifr_name));
380 link_remove(ifr_name);
381 break;
382
383 case KEV_DL_IF_DETACHING :
384 /*
385 * interface detaching
386 */
387 if (dataLen < sizeof(*ev)) {
388 handled = FALSE;
389 break;
390 }
391 copy_if_name(ev, ifr_name, sizeof(ifr_name));
392 interface_detaching(ifr_name);
393 break;
394
395 case KEV_DL_PROTO_ATTACHED :
396 case KEV_DL_PROTO_DETACHED : {
397 struct kev_dl_proto_data * protoEvent;
398
399 protoEvent = (struct kev_dl_proto_data *)event_data;
400 if (dataLen < sizeof(*protoEvent)) {
401 handled = FALSE;
402 break;
403 }
404 copy_if_name(&protoEvent->link_data,
405 ifr_name, sizeof(ifr_name));
406 if (protoEvent->proto_remaining_count == 0) {
407 mark_if_down(ifr_name);
408 } else {
409 mark_if_up(ifr_name);
410 }
411 break;
412 }
413
414 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
415 case KEV_DL_IF_IDLE_ROUTE_REFCNT: {
416 /*
417 * interface route refcnt idle
418 */
419 if (dataLen < sizeof(*ev)) {
420 handled = FALSE;
421 break;
422 }
423 copy_if_name(ev, ifr_name, sizeof(ifr_name));
424 interface_update_idle_state(ifr_name);
425 break;
426 }
427 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
428
429 case KEV_DL_LINK_OFF :
430 case KEV_DL_LINK_ON :
431 /*
432 * update the link status in the store
433 */
434 if (dataLen < sizeof(*ev)) {
435 handled = FALSE;
436 break;
437 }
438 copy_if_name(ev, ifr_name, sizeof(ifr_name));
439 link_update_status(ifr_name, FALSE);
440 break;
441
442 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
443 case KEV_DL_LINK_QUALITY_METRIC_CHANGED: {
444 struct kev_dl_link_quality_metric_data * lqm_data;
445 lqm_data = (struct kev_dl_link_quality_metric_data *) event_data;
446
447 if (dataLen < sizeof(*ev)) {
448 handled = FALSE;
449 break;
450 }
451 copy_if_name(ev, ifr_name, sizeof(ifr_name));
452 interface_update_quality_metric(ifr_name,
453 lqm_data->link_quality_metric);
454 break;
455 }
456 #endif // KEV_DL_LINK_QUALITY_METRIC_CHANGED
457
458 case KEV_DL_SIFFLAGS :
459 case KEV_DL_SIFMETRICS :
460 case KEV_DL_SIFMTU :
461 case KEV_DL_SIFPHYS :
462 case KEV_DL_SIFMEDIA :
463 case KEV_DL_SIFGENERIC :
464 case KEV_DL_ADDMULTI :
465 case KEV_DL_DELMULTI :
466 case KEV_DL_LINK_ADDRESS_CHANGED :
467 case KEV_DL_WAKEFLAGS_CHANGED :
468 #ifdef KEV_DL_IFCAP_CHANGED
469 case KEV_DL_IFCAP_CHANGED :
470 #endif // KEV_DL_IFCAP_CHANGED
471 break;
472
473 default :
474 handled = FALSE;
475 break;
476 }
477 break;
478 }
479 #ifdef KEV_ND6_SUBCLASS
480 case KEV_ND6_SUBCLASS : {
481 eventName = nd6EventNameString(ev_msg->event_code);
482 switch (ev_msg->event_code) {
483 case KEV_KEV_ND6_RA :
484 break;
485
486 default :
487 handled = FALSE;
488 break;
489 }
490 break;
491 }
492 #endif // KEV_ND6_SUBCLASS
493 case KEV_LOG_SUBCLASS : {
494 break;
495 }
496 default :
497 handled = FALSE;
498 break;
499 }
500
501 if (handled == FALSE) {
502 CFStringRef evStr;
503
504 evStr = CFStringCreateWithCString(NULL,
505 (eventName != NULL) ? eventName : "New Apple network subclass",
506 kCFStringEncodingASCII);
507 logEvent(evStr, ev_msg);
508 CFRelease(evStr);
509 }
510 return;
511 }
512
513 static void
514 eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
515 {
516 int so = CFSocketGetNative(s);
517 int status;
518 union {
519 char bytes[1024];
520 struct kern_event_msg ev_msg1; // first kernel event
521 } buf;
522 struct kern_event_msg *ev_msg = &buf.ev_msg1;
523 int offset = 0;
524
525 status = recv(so, &buf, sizeof(buf), 0);
526 if (status == -1) {
527 SCLog(TRUE, LOG_ERR, CFSTR("recv() failed: %s"), strerror(errno));
528 goto error;
529 }
530
531 cache_open();
532
533 while (offset < status) {
534 if ((offset + ev_msg->total_size) > status) {
535 SCLog(TRUE, LOG_NOTICE, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
536 break;
537 }
538
539 switch (ev_msg->vendor_code) {
540 case KEV_VENDOR_APPLE :
541 switch (ev_msg->kev_class) {
542 case KEV_NETWORK_CLASS :
543 processEvent_Apple_Network(ev_msg);
544 break;
545 case KEV_IOKIT_CLASS :
546 case KEV_SYSTEM_CLASS :
547 case KEV_APPLESHARE_CLASS :
548 case KEV_FIREWALL_CLASS :
549 case KEV_IEEE80211_CLASS :
550 break;
551 default :
552 /* unrecognized (Apple) event class */
553 logEvent(CFSTR("New (Apple) class"), ev_msg);
554 break;
555 }
556 break;
557 default :
558 /* unrecognized vendor code */
559 logEvent(CFSTR("New vendor"), ev_msg);
560 break;
561 }
562 offset += ev_msg->total_size;
563 ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset];
564 }
565
566 cache_write(store);
567 cache_close();
568 post_network_changed();
569
570 return;
571
572 error :
573
574 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
575 CFSocketInvalidate(s);
576 return;
577
578 }
579
580 __private_extern__
581 void
582 prime_KernelEventMonitor()
583 {
584 struct ifaddrs *ifap = NULL;
585 struct ifaddrs *scan;
586 int sock = -1;
587
588 SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
589
590 cache_open();
591
592 sock = dgram_socket(AF_INET);
593 if (sock == -1) {
594 SCLog(TRUE, LOG_ERR, CFSTR("could not get interface list, socket() failed: %s"), strerror(errno));
595 goto done;
596 }
597
598 if (getifaddrs(&ifap) == -1) {
599 SCLog(TRUE,
600 LOG_ERR,
601 CFSTR("could not get interface info, getifaddrs() failed: %s"),
602 strerror(errno));
603 goto done;
604 }
605
606 /* update list of interfaces & link status */
607 for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
608 if (scan->ifa_addr == NULL
609 || scan->ifa_addr->sa_family != AF_LINK) {
610 continue;
611 }
612 /* get the per-interface link/media information */
613 link_add(scan->ifa_name);
614 }
615
616 /*
617 * update IPv4 network addresses already assigned to
618 * the interfaces.
619 */
620 interface_update_ipv4(ifap, NULL);
621
622 /*
623 * update IPv6 network addresses already assigned to
624 * the interfaces.
625 */
626 interface_update_ipv6(ifap, NULL);
627
628 freeifaddrs(ifap);
629
630 done:
631 if (sock != -1)
632 close(sock);
633
634 cache_write(store);
635 cache_close();
636
637 network_changed = TRUE;
638 post_network_changed();
639
640 return;
641 }
642
643 static CFStringRef
644 kevSocketCopyDescription(const void *info)
645 {
646 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<kernel event socket>"));
647 }
648
649 __private_extern__
650 void
651 load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
652 {
653 CFSocketContext context = { 0
654 , (void *)1
655 , NULL
656 , NULL
657 , kevSocketCopyDescription
658 };
659 CFSocketRef es;
660 struct kev_request kev_req;
661 CFRunLoopSourceRef rls;
662 int so;
663 int status;
664
665 if (bundleVerbose) {
666 _verbose = TRUE;
667 }
668
669 SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
670 SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
671
672 /* open a "configd" session to allow cache updates */
673 store = SCDynamicStoreCreate(NULL,
674 CFSTR("Kernel Event Monitor plug-in"),
675 NULL,
676 NULL);
677 if (store == NULL) {
678 SCLog(TRUE, LOG_ERR, CFSTR("SCDnamicStoreCreate() failed: %s"), SCErrorString(SCError()));
679 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
680 return;
681 }
682
683 /* Open an event socket */
684 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
685 if (so != -1) {
686 /* establish filter to return events of interest */
687 kev_req.vendor_code = KEV_VENDOR_APPLE;
688 kev_req.kev_class = KEV_NETWORK_CLASS;
689 kev_req.kev_subclass = KEV_ANY_SUBCLASS;
690 status = ioctl(so, SIOCSKEVFILT, &kev_req);
691 if (status) {
692 SCLog(TRUE, LOG_ERR, CFSTR("could not establish event filter, ioctl() failed: %s"), strerror(errno));
693 (void) close(so);
694 so = -1;
695 }
696 } else {
697 SCLog(TRUE, LOG_ERR, CFSTR("could not open event socket, socket() failed: %s"), strerror(errno));
698 }
699
700 if (so != -1) {
701 int yes = 1;
702
703 status = ioctl(so, FIONBIO, &yes);
704 if (status) {
705 SCLog(TRUE, LOG_ERR, CFSTR("could not set non-blocking io, ioctl() failed: %s"), strerror(errno));
706 (void) close(so);
707 so = -1;
708 }
709 }
710
711 if (so == -1) {
712 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
713 CFRelease(store);
714 return;
715 }
716
717 /* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
718 es = CFSocketCreateWithNative(NULL,
719 so,
720 kCFSocketReadCallBack,
721 eventCallback,
722 &context);
723
724 /* Create and add a run loop source for the event socket */
725 rls = CFSocketCreateRunLoopSource(NULL, es, 0);
726 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
727 CFRelease(rls);
728 CFRelease(es);
729
730 return;
731 }
732
733 #ifdef MAIN
734
735 #include "ev_dlil.c"
736
737 #define appendAddress appendAddress_v4
738 #define getIF getIF_v4
739 #define updateStore updateStore_v4
740 #include "ev_ipv4.c"
741 #undef appendAddress
742 #undef getIF
743 #undef updateStore
744
745 #define appendAddress appendAddress_v6
746 #define getIF getIF_v6
747 #define updateStore updateStore_v6
748 #include "ev_ipv6.c"
749 #undef appendAddress
750 #undef getIF
751 #undef updateStore
752
753 int
754 main(int argc, char **argv)
755 {
756 _sc_log = FALSE;
757 _sc_verbose = (argc > 1) ? TRUE : FALSE;
758
759 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
760 prime_KernelEventMonitor();
761 CFRunLoopRun();
762 /* not reached */
763 exit(0);
764 return 0;
765 }
766 #endif