2  * Copyright (c) 2000-2017 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> 
  62 #include <sys/sysctl.h> 
  63 #include <sys/kern_event.h> 
  64 #if __has_include(<nw/private.h>) 
  65 #include <nw/private.h> 
  66 #else // __has_include(<nw/private.h>) 
  67 #include <network/config.h> 
  68 #endif // __has_include(<nw/private.h>) 
  69 #include <netinet6/nd6.h> 
  71 static dispatch_queue_t                 S_kev_queue
; 
  72 static dispatch_source_t                S_kev_source
; 
  73 __private_extern__ Boolean              network_changed         
= FALSE
; 
  74 __private_extern__ SCDynamicStoreRef    store                   
= NULL
; 
  75 __private_extern__ Boolean              _verbose                
= FALSE
; 
  78 __private_extern__ os_log_t
 
  79 __log_KernelEventMonitor(void) 
  81     static os_log_t     log     
= NULL
; 
  84         log 
= os_log_create("com.apple.SystemConfiguration", "KernelEventMonitor"); 
  91 #define MESSAGES_MAX                    100 
  92 static CFMutableArrayRef                S_messages
; 
  93 static Boolean                          S_messages_modified
; 
  98         S_messages 
= CFArrayCreateMutable(NULL
, 
 100                                           &kCFTypeArrayCallBacks
); 
 107         if (S_messages 
!= NULL
) { 
 108                 CFRelease(S_messages
); 
 115 messages_should_add_message(void) 
 117         if (S_messages 
== NULL
 
 118             || CFArrayGetCount(S_messages
) >= MESSAGES_MAX
) { 
 125 messages_add_message(CFStringRef message
) 
 127         if (messages_should_add_message()) { 
 128                 CFArrayAppendValue(S_messages
, message
); 
 129                 S_messages_modified 
= TRUE
; 
 134 __private_extern__ 
void 
 135 messages_add_msg_with_arg(const char * msg
, const char * arg
) 
 137         if (messages_should_add_message()) { 
 140                 str 
= CFStringCreateWithFormat(NULL
, NULL
, 
 141                                                CFSTR("%12.8f: %s %s"), 
 142                                                CFAbsoluteTimeGetCurrent(), 
 144                 messages_add_message(str
); 
 153         if (S_messages 
!= NULL 
&& S_messages_modified
) { 
 154                 SCDynamicStoreSetValue(NULL
, 
 155                                        CFSTR("Plugin:KernelEventMonitor"), 
 157                 S_messages_modified 
= FALSE
; 
 163 check_interface_link_status(const char * if_name
) 
 165         if (S_messages 
== NULL
) { 
 166                 return; /* we're not in early boot of system */ 
 168         link_update_status_if_missing(if_name
); 
 174 dgram_socket(int domain
) 
 178     s 
= socket(domain
, SOCK_DGRAM
, 0); 
 180         SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
)); 
 187 post_network_changed(void) 
 189         if (network_changed
) { 
 192                 status 
= notify_post(_SC_NOTIFY_NETWORK_CHANGE
); 
 193                 if (status 
!= NOTIFY_STATUS_OK
) { 
 194                         SC_log(LOG_NOTICE
, "notify_post() failed: error=%u", status
); 
 197                 network_changed 
= FALSE
; 
 204 logEvent(CFStringRef evStr
, struct kern_event_msg 
*ev_msg
) 
 213         SC_log(LOG_DEBUG
, "%@ event:", evStr
); 
 214         SC_log(LOG_DEBUG
, "  Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d", 
 219               ev_msg
->kev_subclass
, 
 221         for (i 
= 0, j 
= KEV_MSG_HEADER_SIZE
; j 
< ev_msg
->total_size
; i
++, j
+=4) { 
 222                 SC_log(LOG_DEBUG
, "  Event data[%2d] = %08x", i
, ev_msg
->event_data
[i
]); 
 227 copy_if_name(const struct net_event_data 
* ev
, char * ifr_name
, int ifr_len
) 
 229         snprintf(ifr_name
, ifr_len
, "%s%d", ev
->if_name
, ev
->if_unit
); 
 233 static uint8_t info_zero
[DLIL_MODARGLEN
]; 
 236 processEvent_Apple_Network(struct kern_event_msg 
*ev_msg
) 
 238         size_t      dataLen     
= (ev_msg
->total_size 
- KEV_MSG_HEADER_SIZE
); 
 239         void *      event_data  
= &ev_msg
->event_data
[0]; 
 240         char        ifr_name
[IFNAMSIZ
]; 
 241         Boolean     handled     
= TRUE
; 
 243         switch (ev_msg
->kev_subclass
) { 
 244                 case KEV_INET_SUBCLASS 
: { 
 245                         switch (ev_msg
->event_code
) { 
 246                                 case KEV_INET_NEW_ADDR 
: 
 247                                 case KEV_INET_CHANGED_ADDR 
: 
 248                                 case KEV_INET_ADDR_DELETED 
: 
 249                                 case KEV_INET_SIFDSTADDR 
: 
 250                                 case KEV_INET_SIFBRDADDR 
: 
 251                                 case KEV_INET_SIFNETMASK 
: { 
 252                                         struct kev_in_data 
* ev
; 
 254                                         ev 
= (struct kev_in_data 
*)event_data
; 
 255                                         if (dataLen 
< sizeof(*ev
)) { 
 259                                         copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 260                                         SC_log(LOG_INFO
, "Process IPv4 address change: %s: %d", (char *)ifr_name
, ev_msg
->event_code
); 
 261                                         ipv4_interface_update(NULL
, ifr_name
); 
 262                                         if (ev_msg
->event_code
 
 263                                             != KEV_INET_ADDR_DELETED
) { 
 264                                                 check_interface_link_status(ifr_name
); 
 268                                 case KEV_INET_ARPCOLLISION 
: { 
 269                                         struct kev_in_collision 
* ev
; 
 271                                         ev 
= (struct kev_in_collision 
*)event_data
; 
 272                                         if ((dataLen 
< sizeof(*ev
)) 
 273                                             || (dataLen 
< (sizeof(*ev
) + ev
->hw_len
))) { 
 277                                         copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 278                                         SC_log(LOG_INFO
, "Process ARP collision: %s", (char *)ifr_name
); 
 279                                         ipv4_arp_collision(ifr_name
, 
 285 #if     !TARGET_OS_IPHONE 
 286                                 case KEV_INET_PORTINUSE 
: { 
 287                                         struct kev_in_portinuse 
* ev
; 
 288                                         ev 
= (struct kev_in_portinuse 
*)event_data
; 
 289                                         if (dataLen 
< sizeof(*ev
)) { 
 293                                         SC_log(LOG_INFO
, "Process port-in-use: %hu, %u", ev
->port
, ev
->req_pid
); 
 294                                         ipv4_port_in_use(ev
->port
, ev
->req_pid
); 
 297 #endif  /* !TARGET_OS_IPHONE */ 
 298                                 case KEV_INET_ARPRTRFAILURE
: { 
 299                                         const struct kev_in_arpfailure 
* ev
; 
 301                                         ev 
= (const struct kev_in_arpfailure 
*)event_data
; 
 302                                         if (dataLen 
< sizeof(*ev
)) { 
 306                                         copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 307                                         SC_log(LOG_INFO
, "Process router ARP failure: %s", (char *)ifr_name
); 
 308                                         ipv4_router_arp_failure(ifr_name
); 
 311                                 case KEV_INET_ARPRTRALIVE
: { 
 312                                         const struct kev_in_arpalive 
* ev
; 
 314                                         ev 
= (const struct kev_in_arpalive 
*)event_data
; 
 315                                         if (dataLen 
< sizeof(*ev
)) { 
 319                                         copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 320                                         SC_log(LOG_INFO
, "Process router ARP alive: %s", (char *)ifr_name
); 
 321                                         ipv4_router_arp_alive(ifr_name
); 
 330                 case KEV_INET6_SUBCLASS 
: { 
 331                         struct kev_in6_data 
* ev
; 
 333                         ev 
= (struct kev_in6_data 
*)event_data
; 
 334                         switch (ev_msg
->event_code
) { 
 335                                 case KEV_INET6_NEW_USER_ADDR 
: 
 336                                 case KEV_INET6_CHANGED_ADDR 
: 
 337                                 case KEV_INET6_ADDR_DELETED 
: 
 338                                 case KEV_INET6_NEW_LL_ADDR 
: 
 339                                 case KEV_INET6_NEW_RTADV_ADDR 
: 
 340                                         if (dataLen 
< sizeof(*ev
)) { 
 344                                         copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 345                                         SC_log(LOG_INFO
, "Process IPv6 address change: %s: %d", (char *)ifr_name
, ev_msg
->event_code
); 
 346                                         interface_update_ipv6(NULL
, ifr_name
); 
 347                                         if (ev_msg
->event_code 
== KEV_INET6_NEW_USER_ADDR
 
 348                                             && (ev
->ia6_flags 
& IN6_IFF_DUPLICATED
) != 0) { 
 349                                                 ipv6_duplicated_address(ifr_name
, 
 350                                                                         &ev
->ia_addr
.sin6_addr
, 
 354                                         if (ev_msg
->event_code
 
 355                                             != KEV_INET6_ADDR_DELETED
) { 
 356                                                 check_interface_link_status(ifr_name
); 
 360                                 case KEV_INET6_REQUEST_NAT64_PREFIX 
: 
 361                                         if (dataLen 
< sizeof(*ev
)) { 
 365                                         copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 366                                         SC_log(LOG_INFO
, "Process NAT64 prefix request: %s", (char *)ifr_name
); 
 367                                         nat64_prefix_request(ifr_name
); 
 376                 case KEV_DL_SUBCLASS 
: { 
 377                         struct net_event_data 
* ev
; 
 379                         ev 
= (struct net_event_data 
*)event_data
; 
 380                         switch (ev_msg
->event_code
) { 
 381                                 case KEV_DL_IF_ATTACHED 
: 
 383                                          * new interface added 
 385                                         if (dataLen 
< sizeof(*ev
)) { 
 389                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 390                                         SC_log(LOG_INFO
, "Process interface attach: %s", (char *)ifr_name
); 
 394                                 case KEV_DL_IF_DETACHED 
: 
 398                                         if (dataLen 
< sizeof(*ev
)) { 
 402                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 403                                         SC_log(LOG_INFO
, "Process interface detach: %s", (char *)ifr_name
); 
 404                                         link_remove(ifr_name
); 
 407                                 case KEV_DL_IF_DETACHING 
: 
 409                                          * interface detaching 
 411                                         if (dataLen 
< sizeof(*ev
)) { 
 415                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 416                                         SC_log(LOG_INFO
, "Process interface detaching: %s", (char *)ifr_name
); 
 417                                         interface_detaching(ifr_name
); 
 420                                 case KEV_DL_PROTO_ATTACHED 
: 
 421                                 case KEV_DL_PROTO_DETACHED 
: { 
 422                                         struct kev_dl_proto_data 
* protoEvent
; 
 424                                         protoEvent 
= (struct kev_dl_proto_data 
*)event_data
; 
 425                                         if (dataLen 
< sizeof(*protoEvent
)) { 
 429                                         copy_if_name(&protoEvent
->link_data
, 
 430                                                      ifr_name
, sizeof(ifr_name
)); 
 431                                         SC_log(LOG_INFO
, "Process protocol %s: %s (pf=%d, n=%d)", 
 432                                                  (ev_msg
->event_code 
== KEV_DL_PROTO_ATTACHED
) ? "attach" : "detach", 
 434                                                  protoEvent
->proto_family
, 
 435                                                  protoEvent
->proto_remaining_count
); 
 439 #ifdef  KEV_DL_IF_IDLE_ROUTE_REFCNT 
 440                                 case KEV_DL_IF_IDLE_ROUTE_REFCNT
: { 
 442                                          * interface route refcnt idle 
 444                                         if (dataLen 
< sizeof(*ev
)) { 
 448                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 449                                         SC_log(LOG_INFO
, "Process interface idle: %s", (char *)ifr_name
); 
 450                                         interface_update_idle_state(ifr_name
); 
 453 #endif  // KEV_DL_IF_IDLE_ROUTE_REFCNT 
 455                                 case KEV_DL_LINK_OFF 
: 
 456                                 case KEV_DL_LINK_ON 
: 
 458                                          * update the link status in the store 
 460                                         if (dataLen 
< sizeof(*ev
)) { 
 464                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 465                                         SC_log(LOG_INFO
, "Process interface link %s: %s", 
 466                                                  (ev_msg
->event_code 
== KEV_DL_LINK_ON
) ? "up" : "down", 
 468                                         link_update_status(ifr_name
, FALSE
, FALSE
); 
 471 #ifdef  KEV_DL_LINK_QUALITY_METRIC_CHANGED 
 472                                 case KEV_DL_LINK_QUALITY_METRIC_CHANGED
: { 
 473                                         struct kev_dl_link_quality_metric_data 
* lqm_data
; 
 474                                         lqm_data 
= (struct kev_dl_link_quality_metric_data 
*) event_data
; 
 476                                         if (dataLen 
< sizeof(*ev
)) { 
 480                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 481                                         SC_log(LOG_INFO
, "Process interface quality: %s (q=%d)", 
 483                                                  lqm_data
->link_quality_metric
); 
 484                                         interface_update_quality_metric(ifr_name
, 
 485                                                                    lqm_data
->link_quality_metric
); 
 488 #endif  // KEV_DL_LINK_QUALITY_METRIC_CHANGED 
 491                                 case KEV_DL_ISSUES
: { 
 492                                         struct kev_dl_issues 
*issues
; 
 494                                         issues 
= (struct kev_dl_issues 
*)event_data
; 
 495                                         if (dataLen 
< sizeof(*ev
)) { 
 499                                         copy_if_name(ev
, ifr_name
, sizeof(ifr_name
)); 
 500                                         SC_log(LOG_INFO
, "Process interface link issues: %s", 
 502                                         interface_update_link_issues(ifr_name
, 
 507                                                                      (bcmp(issues
->info
, info_zero
, DLIL_MODARGLEN
) != 0) 
 512 #endif  // KEV_DL_ISSUES 
 520 #ifdef  KEV_NETPOLICY_SUBCLASS 
 521                 case KEV_NETPOLICY_SUBCLASS 
: { 
 524 #endif  // KEV_NETPOLICY_SUBCLASS 
 526 #ifdef  KEV_SOCKET_SUBCLASS 
 527                 case KEV_SOCKET_SUBCLASS 
: { 
 530 #endif  // KEV_SOCKET_SUBCLASS 
 532 #ifdef  KEV_ND6_SUBCLASS 
 533                 case KEV_ND6_SUBCLASS 
: { 
 534                         struct kev_nd6_event 
* ev
; 
 536                         ev 
= (struct kev_nd6_event 
*)event_data
; 
 537                         switch (ev_msg
->event_code
) { 
 538                         case KEV_ND6_ADDR_DETACHED 
: 
 539                         case KEV_ND6_ADDR_DEPRECATED 
: 
 540                         case KEV_ND6_ADDR_EXPIRED 
: 
 541                                 if (dataLen 
< sizeof(*ev
)) { 
 545                                 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 546                                 SC_log(LOG_INFO
, "Process ND6 address change: %s: %d", (char *)ifr_name
, ev_msg
->event_code
); 
 547                                 interface_update_ipv6(NULL
, ifr_name
); 
 549                         case KEV_ND6_RTR_EXPIRED 
: 
 550                                 if (dataLen 
< sizeof(*ev
)) { 
 554                                 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
)); 
 555                                 SC_log(LOG_INFO
, "Process IPv6 router expired: %s: %d", (char *)ifr_name
, ev_msg
->event_code
); 
 556                                 ipv6_router_expired(ifr_name
); 
 563 #endif  // KEV_ND6_SUBCLASS 
 565 #ifdef  KEV_NECP_SUBCLASS 
 566                 case KEV_NECP_SUBCLASS 
: { 
 569 #endif  // KEV_NECP_SUBCLASS 
 571 #ifdef  KEV_NETAGENT_SUBCLASS 
 572                 case KEV_NETAGENT_SUBCLASS 
: { 
 575 #endif  // KEV_NETAGENT_SUBCLASS 
 577 #ifdef  KEV_LOG_SUBCLASS 
 578                 case KEV_LOG_SUBCLASS 
: { 
 581 #endif  // KEV_LOG_SUBCLASS 
 583 #ifdef  KEV_NETEVENT_SUBCLASS 
 584                 case KEV_NETEVENT_SUBCLASS 
: { 
 587 #endif  // KEV_NETEVENT_SUBCLASS 
 594                 logEvent(CFSTR("Error processing (Apple network subclass)"), ev_msg
); 
 600 eventCallback(int so
) 
 604                 struct kern_event_msg   ev_msg1
;        // first kernel event 
 606         struct kern_event_msg   
*ev_msg         
= &buf
.ev_msg1
; 
 610         status 
= recv(so
, &buf
, sizeof(buf
), 0); 
 612                 SC_log(LOG_NOTICE
, "recv() failed: %s", strerror(errno
)); 
 618         while (offset 
< status
) { 
 619                 if ((offset 
+ (ssize_t
)ev_msg
->total_size
) > status
) { 
 620                         SC_log(LOG_NOTICE
, "missed SYSPROTO_EVENT event, buffer not big enough"); 
 624                 switch (ev_msg
->vendor_code
) { 
 625                         case KEV_VENDOR_APPLE 
: 
 626                                 switch (ev_msg
->kev_class
) { 
 627                                         case KEV_NETWORK_CLASS 
: 
 628                                                 processEvent_Apple_Network(ev_msg
); 
 638                 offset 
+= ev_msg
->total_size
; 
 639                 ev_msg 
= (struct kern_event_msg 
*)(void *)&buf
.bytes
[offset
]; 
 644         post_network_changed(); 
 651 __private_extern__ 
void 
 652 config_new_interface(const char * ifname
) 
 654         xpc_object_t if_list
; 
 656         if (ifname 
== NULL
) { 
 657                 network_config_check_interface_settings(NULL
); 
 660         if_list 
= xpc_array_create(NULL
, 0); 
 661         xpc_array_set_string(if_list
, XPC_ARRAY_APPEND
, ifname
); 
 662         network_config_check_interface_settings(if_list
); 
 663         xpc_release(if_list
); 
 668 update_interfaces(const char * msg
, Boolean first_time
) 
 670         Boolean                 added 
= FALSE
; 
 671         struct ifaddrs 
*        ifap 
= NULL
; 
 672         CFMutableArrayRef       ifList 
= NULL
; 
 673         struct ifaddrs 
*        scan
; 
 675         if (getifaddrs(&ifap
) == -1) { 
 676                 messages_add_msg_with_arg("getifaddrs", strerror(errno
)); 
 677                 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
)); 
 681         /* update list of interfaces & link status */ 
 682         ifList 
= interfaceListCopy(); 
 683         for (scan 
= ifap
; scan 
!= NULL
; scan 
= scan
->ifa_next
) { 
 684                 if (scan
->ifa_addr 
== NULL
 
 685                     || scan
->ifa_addr
->sa_family 
!= AF_LINK
) { 
 688                 /* get the per-interface link/media information */ 
 689                 if (interfaceListAddInterface(ifList
, scan
->ifa_name
)) { 
 690                         messages_add_msg_with_arg(msg
, scan
->ifa_name
); 
 693                                 config_new_interface(scan
->ifa_name
); 
 698         /* update the global list if an interface was added */ 
 700                 interfaceListUpdate(ifList
); 
 704         /* update IPv4/IPv6 addresses that are already assigned */ 
 706                 ipv4_interface_update(ifap
, NULL
); 
 707                 interface_update_ipv6(ifap
, NULL
); 
 714                 /* tell networkd to get the interface list itself */ 
 715                 config_new_interface(NULL
); 
 720 #define TIMER_INTERVAL          (6LL * NSEC_PER_SEC) 
 721 #define MAX_TIMER_COUNT         20 
 724 check_for_new_interfaces(void * context
); 
 729         dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW
, TIMER_INTERVAL
), 
 732                          check_for_new_interfaces
); 
 737 check_for_new_interfaces(void * context
) 
 739 #pragma unused(context) 
 745         /* update KEV driven content in case a message got dropped */ 
 746         snprintf(msg
, sizeof(msg
), "update %d (of %d)", count
, MAX_TIMER_COUNT
); 
 748         update_interfaces(msg
, FALSE
); 
 753         /* schedule the next timer, if needed */ 
 754         if (count 
< MAX_TIMER_COUNT
) { 
 767         SC_log(LOG_DEBUG
, "prime() called"); 
 771         update_interfaces("prime", TRUE
); 
 775         network_changed 
= TRUE
; 
 776         post_network_changed(); 
 779         /* start handling kernel events */ 
 780         dispatch_resume(S_kev_source
); 
 782         /* schedule polling timer */ 
 791 prime_KernelEventMonitor() 
 793         dispatch_async(S_kev_queue
, ^{ prime(); }); 
 798 initialize_store(void) 
 800         store 
= SCDynamicStoreCreate(NULL
, 
 801                                      CFSTR("Kernel Event Monitor plug-in"), 
 805                 SC_log(LOG_ERR
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError())); 
 814 load_KernelEventMonitor(CFBundleRef bundle
, Boolean bundleVerbose
) 
 816         struct kev_request      kev_req
; 
 824         SC_log(LOG_DEBUG
, "load() called"); 
 825         SC_log(LOG_DEBUG
, "  bundle ID = %@", CFBundleGetIdentifier(bundle
)); 
 827         if (!initialize_store()) { 
 828                 SC_log(LOG_ERR
, "kernel event monitor disabled"); 
 832         /* Open an event socket */ 
 833         so 
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
); 
 835                 /* establish filter to return events of interest */ 
 836                 kev_req
.vendor_code  
= KEV_VENDOR_APPLE
; 
 837                 kev_req
.kev_class    
= KEV_NETWORK_CLASS
; 
 838                 kev_req
.kev_subclass 
= KEV_ANY_SUBCLASS
; 
 839                 status 
= ioctl(so
, SIOCSKEVFILT
, &kev_req
); 
 841                         SC_log(LOG_ERR
, "could not establish event filter, ioctl() failed: %s", strerror(errno
)); 
 846                 SC_log(LOG_ERR
, "could not open event socket, socket() failed: %s", strerror(errno
)); 
 852                 status 
= ioctl(so
, FIONBIO
, &yes
); 
 854                         SC_log(LOG_ERR
, "could not set non-blocking io, ioctl() failed: %s", strerror(errno
)); 
 861                 SC_log(LOG_ERR
, "kernel event monitor disabled"); 
 866         S_kev_queue 
= dispatch_queue_create("com.apple.SystemConfiguration.KernelEventMonitor", NULL
); 
 868                 = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, so
, 0, S_kev_queue
); 
 869         dispatch_source_set_cancel_handler(S_kev_source
, ^{ 
 872         dispatch_source_set_event_handler(S_kev_source
, ^{ 
 873                 os_activity_t   activity
; 
 876                 activity 
= os_activity_create("processing network kernel events", 
 878                                               OS_ACTIVITY_FLAG_DEFAULT
); 
 879                 os_activity_scope(activity
); 
 881                 ok 
= eventCallback(so
); 
 883                         SC_log(LOG_ERR
, "kernel event monitor disabled"); 
 884                         dispatch_source_cancel(S_kev_source
); 
 887                 os_release(activity
); 
 889         // NOTE: dispatch_resume() will be called in prime() 
 898 #define appendAddress   appendAddress_v4 
 899 #define getIF           getIF_v4 
 900 #define updateStore     updateStore_v4 
 906 #define appendAddress   appendAddress_v6 
 907 #define getIF           getIF_v6 
 908 #define updateStore     updateStore_v6 
 915 main(int argc
, char **argv
) 
 918         _sc_verbose 
= (argc 
> 1) ? TRUE 
: FALSE
; 
 920         load_KernelEventMonitor(CFBundleGetMainBundle(), (argc 
> 1) ? TRUE 
: FALSE
); 
 921         prime_KernelEventMonitor();