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