2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
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
33 * August 8, 2002 Allan Nathanson <ajn@apple.com>
34 * - added support for KEV_INET6_xxx events
36 * January 6, 2002 Jessica Vazquez <vazquez@apple.com>
37 * - added handling for KEV_ATALK_xxx events
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
45 * June 23, 2001 Allan Nathanson <ajn@apple.com>
46 * - update to public SystemConfiguration.framework APIs
48 * May 17, 2001 Allan Nathanson <ajn@apple.com>
49 * - add/maintain per-interface address/netmask/destaddr information
50 * in the dynamic store.
52 * June 30, 2000 Allan Nathanson <ajn@apple.com>
64 #define KEV_LOG_SUBCLASS 10
66 static const char *inetEventName
[] = {
69 "INET address changed",
70 "INET address deleted",
71 "INET destination address changed",
72 "INET broadcast address changed",
73 "INET netmask changed",
78 static const char *dlEventName
[] = {
89 "KEV_DL_IF_DETACHING",
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",
100 #ifdef KEV_DL_IFCAP_CHANGED
101 "KEV_DL_IFCAP_CHANGED",
103 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
104 "KEV_DL_LINK_QUALITY_METRIC_CHANGED",
106 #ifdef KEV_DL_NODE_PRESENCE
107 "KEV_DL_NODE_PRESENCE"
109 #ifdef KEV_DL_NODE_ABSENCE
110 "KEV_DL_NODE_ABSENCE"
112 #ifdef KEV_DL_MASTER_ELECTED
113 "KEV_DL_MASTER_ELECTED"
118 #ifdef KEV_DL_IFDELEGATE_CHANGED
119 "KEV_DL_IFDELEGATE_CHANGED",
123 static const char *inet6EventName
[] = {
125 "KEV_INET6_NEW_USER_ADDR",
126 "KEV_INET6_CHANGED_ADDR",
127 "KEV_INET6_ADDR_DELETED",
128 "KEV_INET6_NEW_LL_ADDR",
129 "KEV_INET6_NEW_RTADV_ADDR",
130 "KEV_INET6_DEFROUTER"
133 #ifdef KEV_ND6_SUBCLASS
134 static const char *nd6EventNameString
[] = {
138 #endif // KEV_ND6_SUBCLASS
140 static dispatch_queue_t S_kev_queue
;
141 static dispatch_source_t S_kev_source
;
142 __private_extern__ Boolean network_changed
= FALSE
;
143 __private_extern__ SCDynamicStoreRef store
= NULL
;
144 __private_extern__ Boolean _verbose
= FALSE
;
148 dgram_socket(int domain
)
150 return (socket(domain
, SOCK_DGRAM
, 0));
154 ifflags_set(int s
, char * name
, short flags
)
159 bzero(&ifr
, sizeof(ifr
));
160 strlcpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
161 ret
= ioctl(s
, SIOCGIFFLAGS
, (caddr_t
)&ifr
);
165 ifr
.ifr_flags
|= flags
;
166 return (ioctl(s
, SIOCSIFFLAGS
, &ifr
));
170 ifflags_clear(int s
, char * name
, short flags
)
175 bzero(&ifr
, sizeof(ifr
));
176 strlcpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
177 ret
= ioctl(s
, SIOCGIFFLAGS
, (caddr_t
)&ifr
);
181 ifr
.ifr_flags
&= ~flags
;
182 return (ioctl(s
, SIOCSIFFLAGS
, &ifr
));
186 mark_if_up(char * name
)
188 int s
= dgram_socket(AF_INET
);
191 ifflags_set(s
, name
, IFF_UP
);
196 mark_if_down(char * name
)
198 int s
= dgram_socket(AF_INET
);
201 ifflags_clear(s
, name
, IFF_UP
);
206 post_network_changed(void)
208 if (network_changed
) {
211 status
= notify_post(_SC_NOTIFY_NETWORK_CHANGE
);
212 if (status
!= NOTIFY_STATUS_OK
) {
213 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_post() failed: error=%u"), status
);
216 network_changed
= FALSE
;
223 logEvent(CFStringRef evStr
, struct kern_event_msg
*ev_msg
)
232 SCLog(TRUE
, LOG_DEBUG
, CFSTR("%@ event:"), evStr
);
233 SCLog(TRUE
, LOG_DEBUG
,
234 CFSTR(" Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d"),
239 ev_msg
->kev_subclass
,
241 for (i
= 0, j
= KEV_MSG_HEADER_SIZE
; j
< ev_msg
->total_size
; i
++, j
+=4) {
242 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" Event data[%2d] = %08x"), i
, ev_msg
->event_data
[i
]);
247 inetEventNameString(uint32_t event_code
)
249 if (event_code
< sizeof(inetEventName
) / sizeof(inetEventName
[0])) {
250 return (inetEventName
[event_code
]);
252 return ("New Apple network INET subcode");
256 inet6EventNameString(uint32_t event_code
)
258 if (event_code
< sizeof(inet6EventName
) / sizeof(inet6EventName
[0])) {
259 return (inet6EventName
[event_code
]);
261 return ("New Apple network INET6 subcode");
265 dlEventNameString(uint32_t event_code
)
267 if (event_code
< sizeof(dlEventName
) / sizeof(dlEventName
[0])) {
268 return (dlEventName
[event_code
]);
270 return ("New Apple network DL subcode");
274 copy_if_name(const struct net_event_data
* ev
, char * ifr_name
, int ifr_len
)
276 snprintf(ifr_name
, ifr_len
, "%s%d", ev
->if_name
, ev
->if_unit
);
280 static uint8_t info_zero
[DLIL_MODARGLEN
];
283 processEvent_Apple_Network(struct kern_event_msg
*ev_msg
)
285 const char * eventName
= NULL
;
286 int dataLen
= (ev_msg
->total_size
- KEV_MSG_HEADER_SIZE
);
287 void * event_data
= &ev_msg
->event_data
[0];
288 Boolean handled
= TRUE
;
289 char ifr_name
[IFNAMSIZ
];
291 switch (ev_msg
->kev_subclass
) {
292 case KEV_INET_SUBCLASS
: {
293 eventName
= inetEventNameString(ev_msg
->event_code
);
294 switch (ev_msg
->event_code
) {
295 case KEV_INET_NEW_ADDR
:
296 case KEV_INET_CHANGED_ADDR
:
297 case KEV_INET_ADDR_DELETED
:
298 case KEV_INET_SIFDSTADDR
:
299 case KEV_INET_SIFBRDADDR
:
300 case KEV_INET_SIFNETMASK
: {
301 struct kev_in_data
* ev
;
303 ev
= (struct kev_in_data
*)event_data
;
304 if (dataLen
< sizeof(*ev
)) {
308 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
309 ipv4_interface_update(NULL
, ifr_name
);
312 case KEV_INET_ARPCOLLISION
: {
313 struct kev_in_collision
* ev
;
315 ev
= (struct kev_in_collision
*)event_data
;
316 if ((dataLen
< sizeof(*ev
))
317 || (dataLen
< (sizeof(*ev
) + ev
->hw_len
))) {
321 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
322 ipv4_arp_collision(ifr_name
,
328 #if !TARGET_OS_IPHONE
329 case KEV_INET_PORTINUSE
: {
330 struct kev_in_portinuse
* ev
;
331 ev
= (struct kev_in_portinuse
*)event_data
;
332 if (dataLen
< sizeof(*ev
)) {
336 ipv4_port_in_use(ev
->port
, ev
->req_pid
);
339 #endif /* !TARGET_OS_IPHONE */
340 case KEV_INET_ARPRTRFAILURE
: {
341 const struct kev_in_arpfailure
* ev
;
343 ev
= (const struct kev_in_arpfailure
*)event_data
;
344 if (dataLen
< sizeof(*ev
)) {
348 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
349 ipv4_router_arp_failure(ifr_name
);
352 case KEV_INET_ARPRTRALIVE
: {
353 const struct kev_in_arpalive
* ev
;
355 ev
= (const struct kev_in_arpalive
*)event_data
;
356 if (dataLen
< sizeof(*ev
)) {
360 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
361 ipv4_router_arp_alive(ifr_name
);
370 case KEV_INET6_SUBCLASS
: {
371 struct kev_in6_data
* ev
;
373 eventName
= inet6EventNameString(ev_msg
->event_code
);
374 ev
= (struct kev_in6_data
*)event_data
;
375 switch (ev_msg
->event_code
) {
376 case KEV_INET6_NEW_USER_ADDR
:
377 case KEV_INET6_CHANGED_ADDR
:
378 case KEV_INET6_ADDR_DELETED
:
379 case KEV_INET6_NEW_LL_ADDR
:
380 case KEV_INET6_NEW_RTADV_ADDR
:
381 case KEV_INET6_DEFROUTER
:
382 if (dataLen
< sizeof(*ev
)) {
386 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
387 interface_update_ipv6(NULL
, ifr_name
);
396 case KEV_DL_SUBCLASS
: {
397 struct net_event_data
* ev
;
399 eventName
= dlEventNameString(ev_msg
->event_code
);
400 ev
= (struct net_event_data
*)event_data
;
401 switch (ev_msg
->event_code
) {
402 case KEV_DL_IF_ATTACHED
:
404 * new interface added
406 if (dataLen
< sizeof(*ev
)) {
410 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
414 case KEV_DL_IF_DETACHED
:
418 if (dataLen
< sizeof(*ev
)) {
422 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
423 link_remove(ifr_name
);
426 case KEV_DL_IF_DETACHING
:
428 * interface detaching
430 if (dataLen
< sizeof(*ev
)) {
434 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
435 interface_detaching(ifr_name
);
438 case KEV_DL_PROTO_ATTACHED
:
439 case KEV_DL_PROTO_DETACHED
: {
440 struct kev_dl_proto_data
* protoEvent
;
442 protoEvent
= (struct kev_dl_proto_data
*)event_data
;
443 if (dataLen
< sizeof(*protoEvent
)) {
447 copy_if_name(&protoEvent
->link_data
,
448 ifr_name
, sizeof(ifr_name
));
449 if (protoEvent
->proto_remaining_count
== 0) {
450 mark_if_down(ifr_name
);
452 mark_if_up(ifr_name
);
457 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
458 case KEV_DL_IF_IDLE_ROUTE_REFCNT
: {
460 * interface route refcnt idle
462 if (dataLen
< sizeof(*ev
)) {
466 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
467 interface_update_idle_state(ifr_name
);
470 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
472 case KEV_DL_LINK_OFF
:
473 case KEV_DL_LINK_ON
:
475 * update the link status in the store
477 if (dataLen
< sizeof(*ev
)) {
481 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
482 link_update_status(ifr_name
, FALSE
);
485 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
486 case KEV_DL_LINK_QUALITY_METRIC_CHANGED
: {
487 struct kev_dl_link_quality_metric_data
* lqm_data
;
488 lqm_data
= (struct kev_dl_link_quality_metric_data
*) event_data
;
490 if (dataLen
< sizeof(*ev
)) {
494 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
495 interface_update_quality_metric(ifr_name
,
496 lqm_data
->link_quality_metric
);
499 #endif // KEV_DL_LINK_QUALITY_METRIC_CHANGED
502 case KEV_DL_ISSUES
: {
503 struct kev_dl_issues
*issues
;
505 issues
= (struct kev_dl_issues
*)event_data
;
506 if (dataLen
< sizeof(*ev
)) {
510 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
511 interface_update_link_issues(ifr_name
,
516 (bcmp(issues
->info
, info_zero
, DLIL_MODIDLEN
) != 0)
521 #endif // KEV_DL_ISSUES
523 case KEV_DL_SIFFLAGS
:
524 case KEV_DL_SIFMETRICS
:
526 case KEV_DL_SIFPHYS
:
527 case KEV_DL_SIFMEDIA
:
528 case KEV_DL_SIFGENERIC
:
529 case KEV_DL_ADDMULTI
:
530 case KEV_DL_DELMULTI
:
531 case KEV_DL_LINK_ADDRESS_CHANGED
:
532 case KEV_DL_WAKEFLAGS_CHANGED
:
533 #ifdef KEV_DL_IFCAP_CHANGED
534 case KEV_DL_IFCAP_CHANGED
:
535 #endif // KEV_DL_IFCAP_CHANGED
544 #ifdef KEV_ND6_SUBCLASS
545 case KEV_ND6_SUBCLASS
: {
546 eventName
= nd6EventNameString(ev_msg
->event_code
);
547 switch (ev_msg
->event_code
) {
548 case KEV_KEV_ND6_RA
:
557 #endif // KEV_ND6_SUBCLASS
558 case KEV_LOG_SUBCLASS
: {
566 if (handled
== FALSE
) {
569 evStr
= CFStringCreateWithCString(NULL
,
570 (eventName
!= NULL
) ? eventName
: "New Apple network subclass",
571 kCFStringEncodingASCII
);
572 logEvent(evStr
, ev_msg
);
579 eventCallback(int so
)
584 struct kern_event_msg ev_msg1
; // first kernel event
586 struct kern_event_msg
*ev_msg
= &buf
.ev_msg1
;
589 status
= recv(so
, &buf
, sizeof(buf
), 0);
591 SCLog(TRUE
, LOG_ERR
, CFSTR("recv() failed: %s"), strerror(errno
));
597 while (offset
< status
) {
598 if ((offset
+ ev_msg
->total_size
) > status
) {
599 SCLog(TRUE
, LOG_NOTICE
, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
603 switch (ev_msg
->vendor_code
) {
604 case KEV_VENDOR_APPLE
:
605 switch (ev_msg
->kev_class
) {
606 case KEV_NETWORK_CLASS
:
607 processEvent_Apple_Network(ev_msg
);
609 case KEV_IOKIT_CLASS
:
610 case KEV_SYSTEM_CLASS
:
611 case KEV_APPLESHARE_CLASS
:
612 case KEV_FIREWALL_CLASS
:
613 case KEV_IEEE80211_CLASS
:
616 /* unrecognized (Apple) event class */
617 logEvent(CFSTR("New (Apple) class"), ev_msg
);
622 /* unrecognized vendor code */
623 logEvent(CFSTR("New vendor"), ev_msg
);
626 offset
+= ev_msg
->total_size
;
627 ev_msg
= (struct kern_event_msg
*)(void *)&buf
.bytes
[offset
];
632 post_network_changed();
641 struct ifaddrs
*ifap
= NULL
;
642 struct ifaddrs
*scan
;
645 SCLog(_verbose
, LOG_DEBUG
, CFSTR("prime() called"));
649 sock
= dgram_socket(AF_INET
);
651 SCLog(TRUE
, LOG_ERR
, CFSTR("could not get interface list, socket() failed: %s"), strerror(errno
));
655 if (getifaddrs(&ifap
) == -1) {
658 CFSTR("could not get interface info, getifaddrs() failed: %s"),
663 /* update list of interfaces & link status */
664 for (scan
= ifap
; scan
!= NULL
; scan
= scan
->ifa_next
) {
665 if (scan
->ifa_addr
== NULL
666 || scan
->ifa_addr
->sa_family
!= AF_LINK
) {
669 /* get the per-interface link/media information */
670 link_add(scan
->ifa_name
);
674 * update IPv4 network addresses already assigned to
677 ipv4_interface_update(ifap
, NULL
);
680 * update IPv6 network addresses already assigned to
683 interface_update_ipv6(ifap
, NULL
);
694 network_changed
= TRUE
;
695 post_network_changed();
697 /* start handling kernel events */
698 dispatch_resume(S_kev_source
);
706 prime_KernelEventMonitor()
708 dispatch_async(S_kev_queue
, ^{ prime(); });
714 load_KernelEventMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
716 struct kev_request kev_req
;
724 SCLog(_verbose
, LOG_DEBUG
, CFSTR("load() called"));
725 SCLog(_verbose
, LOG_DEBUG
, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle
));
727 /* open a "configd" session to allow cache updates */
728 store
= SCDynamicStoreCreate(NULL
,
729 CFSTR("Kernel Event Monitor plug-in"),
733 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDnamicStoreCreate() failed: %s"), SCErrorString(SCError()));
734 SCLog(TRUE
, LOG_ERR
, CFSTR("kernel event monitor disabled."));
738 /* Open an event socket */
739 so
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
741 /* establish filter to return events of interest */
742 kev_req
.vendor_code
= KEV_VENDOR_APPLE
;
743 kev_req
.kev_class
= KEV_NETWORK_CLASS
;
744 kev_req
.kev_subclass
= KEV_ANY_SUBCLASS
;
745 status
= ioctl(so
, SIOCSKEVFILT
, &kev_req
);
747 SCLog(TRUE
, LOG_ERR
, CFSTR("could not establish event filter, ioctl() failed: %s"), strerror(errno
));
752 SCLog(TRUE
, LOG_ERR
, CFSTR("could not open event socket, socket() failed: %s"), strerror(errno
));
758 status
= ioctl(so
, FIONBIO
, &yes
);
760 SCLog(TRUE
, LOG_ERR
, CFSTR("could not set non-blocking io, ioctl() failed: %s"), strerror(errno
));
767 SCLog(TRUE
, LOG_ERR
, CFSTR("kernel event monitor disabled."));
772 S_kev_queue
= dispatch_queue_create("com.apple.SystemConfiguration.KernelEventMonitor", NULL
);
774 = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, so
, 0, S_kev_queue
);
775 dispatch_source_set_cancel_handler(S_kev_source
, ^{
778 dispatch_source_set_event_handler(S_kev_source
, ^{
781 ok
= eventCallback(so
);
783 SCLog(TRUE
, LOG_ERR
, CFSTR("kernel event monitor disabled."));
784 dispatch_source_cancel(S_kev_source
);
788 // NOTE: dispatch_resume() will be called in prime()
797 #define appendAddress appendAddress_v4
798 #define getIF getIF_v4
799 #define updateStore updateStore_v4
805 #define appendAddress appendAddress_v6
806 #define getIF getIF_v6
807 #define updateStore updateStore_v6
814 main(int argc
, char **argv
)
817 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
819 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
820 prime_KernelEventMonitor();