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