1/* 2 * Copyright (c) 1999-2014 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 * ipconfigd.c 26 * - daemon that configures interfaces using manual settings, 27 * manual with DHCP INFORM, BOOTP, or DHCP 28 */ 29/* 30 * Modification History 31 * 32 * September, 1999 Dieter Siegmund (dieter@apple.com) 33 * - initial revision 34 * 35 * May 8, 2000 Dieter Siegmund (dieter@apple.com) 36 * - re-architected to be event-driven to satisfy mobility 37 * requirements 38 * - converted to use a single main configuration thread 39 * instead of a thread per interface 40 * - removed dependency on objective C 41 * 42 * June 12, 2000 Dieter Siegmund (dieter@apple.com) 43 * - converted to use CFRunLoop 44 * - added ability to change the configuration on the fly, either by 45 * a configuration data change, or having the user send a command 46 * via ipconfig 47 * 48 * July 5, 2000 Dieter Siegmund (dieter@apple.com) 49 * - added code to publish information with configd 50 * - wrote common IP config module to read information from the cache, 51 * and update the default route, DNS, and netinfo parent(s) on the fly 52 * 53 * August 20, 2000 Dieter Siegmund (dieter@apple.com) 54 * - moved common IP config module to configd_plugins/IPMonitor.bproj 55 * - added code to handle information from setup/cache only 56 * 57 * October 4, 2000 Dieter Siegmund (dieter@apple.com) 58 * - added code to handle error cases and force the interface 59 * state to be ready to avoid hanging the system startup in case 60 * there is bad data in the cache 61 * 62 * November 20, 2000 Dieter Siegmund (dieter@apple.com) 63 * - changed to use new preferences keys and service-based configuration 64 * 65 * March 27, 2001 Dieter Siegmund (dieter@apple.com) 66 * - turned ipconfigd into the IPConfiguration bundle 67 * 68 * May 17, 2001 Dieter Siegmund (dieter@apple.com) 69 * - publish information in service state instead of interface state 70 * 71 * June 14, 2001 Dieter Siegmund (dieter@apple.com) 72 * - publish DHCP options in dynamic store, and allow third party 73 * applications to request additional options using a DHCPClient 74 * preference 75 * - add notification handler to automatically force the DHCP client 76 * to renew its lease 77 * 78 * July 12, 2001 Dieter Siegmund (dieter@apple.com) 79 * - don't bother reporting arp collisions with our own interfaces 80 * 81 * July 19, 2001 Dieter Siegmund (dieter@apple.com) 82 * - port to use public SystemConfiguration APIs 83 * 84 * August 28, 2001 Dieter Siegmund (dieter@apple.com) 85 * - when multiple interfaces are configured to be on the same subnet, 86 * keep the subnet route correct and have it follow the service/interface 87 * with the highest priority 88 * - this also eliminates problems with the subnet route getting lost 89 * when an interface is de-configured, yet another interface is on 90 * the same subnet 91 * 92 * September 10, 2001 Dieter Siegmund (dieter@apple.com) 93 * - added multiple service per interface support 94 * - separated ad-hoc/link-local address configuration into its own service 95 * 96 * January 4, 2002 Dieter Siegmund (dieter@apple.com) 97 * - always configure the link-local service on the service with the 98 * highest priority service that's active 99 * - modified link-local service to optionally allocate an IP address; 100 * if we don't allocate an IP, we just set the link-local subnet 101 * - allow a previously failed DHCP service to acquire a link-local IP 102 * address if it later becomes the primary service 103 * - a link-local address will only be allocated when a DHCP service fails, 104 * and it is the primary service, and the G_dhcp_failure_configures_linklocal 105 * is TRUE 106 * 107 * February 1, 2002 Dieter Siegmund (dieter@apple.com) 108 * - make IPConfiguration netboot-aware: 109 * + grab the DHCP information from the packet in the device tree 110 * 111 * May 20, 2002 Dieter Siegmund (dieter@apple.com) 112 * - allocate a link-local address more quickly, after the first 113 * DHCP request fails 114 * - re-structured the automatic link-local service allocation to do 115 * most of the work from a run-loop observer instead of within the 116 * context of the caller; this avoids unnecessary re-entrancy issues 117 * and complexity 118 * 119 * December 3, 2002 Dieter Siegmund (dieter@apple.com) 120 * - add support to detect ARP collisions after we have already 121 * assigned ourselves the address 122 * 123 * June 16, 2003 Dieter Siegmund (dieter@apple.com) 124 * - added support for firewire (IFT_IEEE1394) 125 * 126 * November 19, 2003 Dieter Siegmund (dieter@apple.com) 127 * - added support for VLAN's (IFT_L2VLAN) 128 * 129 * April 13, 2005 Dieter Siegmund (dieter@apple.com) 130 * - added support for multiple link-local services, one per interface 131 * - changed logic to favor a successful service (i.e. one with an IP address) 132 * over simply the highest ranked service per interface 133 * - maintain the link-local subnet on the interface with the highest ranked 134 * active service 135 * 136 * October 20, 2006 Dieter Siegmund (dieter@apple.com) 137 * - resolve the router's MAC address using ARP, and publish that 138 * information to the NetworkSignature in the IPv4 dict 139 * 140 * December 19, 2007 Dieter Siegmund (dieter@apple.com) 141 * - removed subnet route maintenance code since IPMonitor now takes 142 * care of that 143 * 144 * September 4, 2009 Dieter Siegmund (dieter@apple.com) 145 * - added support for IPv6 configuration 146 */ 147 148#include <stdlib.h> 149#include <unistd.h> 150#include <string.h> 151#include <stdio.h> 152#include <sys/types.h> 153#include <sys/param.h> 154#include <sys/sysctl.h> 155#include <sys/wait.h> 156#include <sys/errno.h> 157#include <sys/socket.h> 158#define KERNEL_PRIVATE 159#include <sys/ioctl.h> 160#undef KERNEL_PRIVATE 161#include <ctype.h> 162#include <net/if.h> 163#include <net/ethernet.h> 164#include <net/firewire.h> 165#include <netinet/in.h> 166#include <netinet/udp.h> 167#include <netinet/ip.h> 168#include <netinet/bootp.h> 169#include <arpa/inet.h> 170#include <fcntl.h> 171#include <paths.h> 172#include <syslog.h> 173#include <net/if_types.h> 174#include <mach/boolean.h> 175 176#include <SystemConfiguration/SystemConfiguration.h> 177#include <SystemConfiguration/SCPrivate.h> 178#include <SystemConfiguration/SCValidation.h> 179#include <SystemConfiguration/SCDPlugin.h> 180#include <IOKit/IOMessage.h> 181#include <IOKit/IOKitLib.h> 182#include <IOKit/pwr_mgt/IOPMLib.h> 183#include <IOKit/IOHibernatePrivate.h> 184#include <TargetConditionals.h> 185#include <Availability.h> 186#if ! TARGET_OS_EMBEDDED 187#include <CoreFoundation/CFUserNotification.h> 188#include <CoreFoundation/CFUserNotificationPriv.h> 189#include <IOKit/pwr_mgt/IOPMLibPrivate.h> 190#endif /* ! TARGET_OS_EMBEDDED */ 191 192#include "rfc_options.h" 193#include "dhcp_options.h" 194#include "interfaces.h" 195#include "util.h" 196 197#include "dhcplib.h" 198#include "ioregpath.h" 199 200#include "ipconfig_types.h" 201#include "ipconfigd.h" 202#include "server.h" 203#include "timer.h" 204 205#include "ipconfigd_globals.h" 206#include "ipconfigd_threads.h" 207#include "FDSet.h" 208 209#include "symbol_scope.h" 210#include "cfutil.h" 211#include "sysconfig.h" 212#include "ifutil.h" 213#include "rtutil.h" 214#include "DHCPv6Client.h" 215#include "DHCPv6Socket.h" 216#include "IPConfigurationServiceInternal.h" 217#include "IPConfigurationControlPrefs.h" 218#include "CGA.h" 219#include "IPv6Socket.h" 220 221#define RIFLAGS_IADDR_VALID ((uint32_t)0x1) 222#define RIFLAGS_HWADDR_VALID ((uint32_t)0x2) 223#define RIFLAGS_ARP_VERIFIED ((uint32_t)0x4) 224#define RIFLAGS_ALL_VALID (RIFLAGS_IADDR_VALID | RIFLAGS_HWADDR_VALID | RIFLAGS_ARP_VERIFIED) 225 226#define kARPResolvedIPAddress CFSTR("ARPResolvedIPAddress") 227#define kARPResolvedHardwareAddress CFSTR("ARPResolvedHardwareAddress") 228 229typedef struct { 230 uint32_t flags; 231 struct in_addr iaddr; 232 uint8_t hwaddr[MAX_LINK_ADDR_LEN]; 233} router_info_t; 234 235typedef struct IFState * IFStateRef; 236 237typedef struct { 238 struct in_addr addr; 239 struct in_addr mask; 240} ip_addr_mask_t; 241 242typedef struct { 243 ip_addr_mask_t requested_ip; 244 inet_addrinfo_t info; 245 router_info_t router; 246 absolute_time_t ip_assigned_time; 247 absolute_time_t ip_conflict_time; 248 int ip_conflict_count; 249} ServiceIPv4, * ServiceIPv4Ref; 250 251typedef struct { 252 struct in6_addr addr; 253 int prefix_length; 254} inet6_addr_prefix_t; 255 256typedef struct { 257 inet6_addr_prefix_t requested_ip; 258} ServiceIPv6, * ServiceIPv6Ref; 259 260struct ServiceInfo { 261 CFStringRef serviceID; 262 IFStateRef ifstate; 263 ipconfig_method_t method; 264 ipconfig_status_t status; 265 boolean_t is_dynamic; 266 boolean_t no_publish; 267 boolean_t ready; 268 CFStringRef parent_serviceID; 269 CFStringRef child_serviceID; 270 dispatch_source_t pid_source; 271 void * private; 272#if ! TARGET_OS_EMBEDDED 273 CFUserNotificationRef user_notification; 274 CFRunLoopSourceRef user_rls; 275#endif /* ! TARGET_OS_EMBEDDED */ 276 union { 277 ServiceIPv4 v4; 278 ServiceIPv6 v6; 279 } u; 280}; 281 282typedef struct ActiveDuringSleepInfo { 283 boolean_t needs_attention; 284 boolean_t requested; 285} ActiveDuringSleepInfo, * ActiveDuringSleepInfoRef; 286 287struct IFState { 288 interface_t * if_p; 289 CFStringRef ifname; 290 dynarray_t services; 291 dynarray_t services_v6; 292 ServiceRef linklocal_service_p; 293 boolean_t startup_ready; 294 boolean_t netboot; 295 CFStringRef ssid; 296 struct ether_addr bssid; 297 timer_callout_t * timer; 298 struct in_addr v4_link_local; 299 uint32_t wake_generation; 300 boolean_t disable_perform_nud; 301 boolean_t link_timer_suppressed; 302 CFMutableArrayRef neighbor_advert_list; 303 ActiveDuringSleepInfo active_during_sleep; 304}; 305 306typedef dynarray_t IFStateList_t; 307 308#define IS_IPV4 TRUE 309#define IS_IPV6 FALSE 310 311#ifndef kSCEntNetRefreshConfiguration 312#define kSCEntNetRefreshConfiguration CFSTR("RefreshConfiguration") 313#endif /* kSCEntNetRefreshConfiguration */ 314 315#ifndef kSCEntNetIPv4ARPCollision 316#define kSCEntNetIPv4ARPCollision CFSTR("IPv4ARPCollision") 317#endif /* kSCEntNetIPv4ARPCollision */ 318 319#ifndef kSCEntNetDHCPv6 320#define kSCEntNetDHCPv6 CFSTR("DHCPv6") 321#endif /* kSCEntNetDHCPv6 */ 322 323#ifndef kSCValNetIPv4ConfigMethodFailover 324static const CFStringRef kIPConfigurationConfigMethodFailover = CFSTR("Failover"); 325#define kSCValNetIPv4ConfigMethodFailover kIPConfigurationConfigMethodFailover 326#endif /* kSCValNetIPv4ConfigMethodFailover */ 327 328#ifndef kSCValNetIPv6ConfigMethodLinkLocal 329static const CFStringRef kIPConfigurationIPv6ConfigMethodLinkLocal = CFSTR("LinkLocal"); 330#define kSCValNetIPv6ConfigMethodLinkLocal kIPConfigurationIPv6ConfigMethodLinkLocal 331#endif /* kSCValNetIPv6ConfigMethodLinkLocal */ 332 333 334#ifndef kSCPropNetIPv4FailoverAddressTimeout 335static const CFStringRef kIPConfigurationFailoverAddressTimeout = CFSTR("FailoverAddressTimeout"); 336#define kSCPropNetIPv4FailoverAddressTimeout kIPConfigurationFailoverAddressTimeout 337#endif /* kSCPropNetIPv4FailoverAddressTimeout */ 338 339#ifndef kSCPropNetIgnoreLinkStatus 340static const CFStringRef kIPConfigurationIgnoreLinkStatus = CFSTR("IgnoreLinkStatus"); 341#define kSCPropNetIgnoreLinkStatus kIPConfigurationIgnoreLinkStatus 342#endif /* kSCPropNetIgnoreLinkStatus */ 343 344#ifndef kSCPropNetIPv66to4Relay 345static const CFStringRef kSCPropNetIPv66to4Relay = CFSTR("6to4Relay"); 346#endif /* kSCPropNetIPv66to4Relay */ 347 348#ifndef kSCEntNetInterfaceActiveDuringSleepRequested 349#define kSCEntNetInterfaceActiveDuringSleepRequested CFSTR("ActiveDuringSleepRequested") 350#endif /* kSCEntNetInterfaceActiveDuringSleepRequested */ 351 352#ifndef kSCEntNetInterfaceActiveDuringSleepSupported 353#define kSCEntNetInterfaceActiveDuringSleepSupported CFSTR("ActiveDuringSleepSupported") 354#endif /* kSCEntNetInterfaceActiveDuringSleepSupported */ 355 356#define kDHCPClientPreferencesID CFSTR("DHCPClient.plist") 357#define kDHCPClientApplicationPref CFSTR("Application") 358#define kDHCPRequestedParameterList CFSTR("DHCPRequestedParameterList") 359 360#define kDHCPv6RequestedOptions CFSTR("DHCPv6RequestedOptions") 361 362/* default values */ 363#define MAX_RETRIES 9 364#define INITIAL_WAIT_SECS 1 365#define MAX_WAIT_SECS 8 366#define GATHER_SECS 1 367#define LINK_INACTIVE_WAIT_SECS 0 368#define LINK_INACTIVE_WAIT_USECS (100 * 1000) 369#define DHCP_INIT_REBOOT_RETRY_COUNT 2 370#define DHCP_SELECT_RETRY_COUNT 3 371#define DHCP_ALLOCATE_LINKLOCAL_AT_RETRY_COUNT 4 372#define DHCP_ROUTER_ARP_AT_RETRY_COUNT 7 373#define DHCP_FAILURE_CONFIGURES_LINKLOCAL TRUE 374#define DHCP_SUCCESS_DECONFIGURES_LINKLOCAL TRUE 375#define DHCP_LOCAL_HOSTNAME_LENGTH_MAX 15 376#define DISCOVER_ROUTER_MAC_ADDRESS_SECS 60 377#define DEFEND_IP_ADDRESS_INTERVAL_SECS 10 378#define DEFEND_IP_ADDRESS_COUNT 5 379#define DHCP_LEASE_WRITE_T1_THRESHOLD_SECS 3600 380#define MANUAL_CONFLICT_RETRY_INTERVAL_SECS 300 381 382#define USER_ERROR 1 383#define UNEXPECTED_ERROR 2 384#define TIMEOUT_ERROR 3 385 386/* global variables */ 387PRIVATE_EXTERN uint16_t G_client_port = IPPORT_BOOTPC; 388PRIVATE_EXTERN boolean_t G_dhcp_accepts_bootp = FALSE; 389PRIVATE_EXTERN boolean_t G_dhcp_failure_configures_linklocal 390 = DHCP_FAILURE_CONFIGURES_LINKLOCAL; 391PRIVATE_EXTERN boolean_t G_dhcp_success_deconfigures_linklocal 392 = DHCP_SUCCESS_DECONFIGURES_LINKLOCAL; 393PRIVATE_EXTERN int G_dhcp_allocate_linklocal_at_retry_count 394 = DHCP_ALLOCATE_LINKLOCAL_AT_RETRY_COUNT; 395PRIVATE_EXTERN int G_dhcp_router_arp_at_retry_count 396 = DHCP_ROUTER_ARP_AT_RETRY_COUNT; 397PRIVATE_EXTERN int G_dhcp_init_reboot_retry_count 398 = DHCP_INIT_REBOOT_RETRY_COUNT; 399PRIVATE_EXTERN int G_dhcp_select_retry_count 400 = DHCP_SELECT_RETRY_COUNT; 401PRIVATE_EXTERN int G_dhcp_lease_write_t1_threshold_secs 402 = DHCP_LEASE_WRITE_T1_THRESHOLD_SECS; 403PRIVATE_EXTERN uint16_t G_server_port = IPPORT_BOOTPS; 404PRIVATE_EXTERN int G_manual_conflict_retry_interval_secs 405 = MANUAL_CONFLICT_RETRY_INTERVAL_SECS; 406 407PRIVATE_EXTERN boolean_t G_is_netboot = FALSE; 408 409/* 410 * Static: S_link_inactive_secs 411 * Purpose: 412 * Time to wait after the link goes inactive before unpublishing 413 * the interface state information 414 */ 415static struct timeval S_link_inactive_secs = { 416 LINK_INACTIVE_WAIT_SECS, 417 LINK_INACTIVE_WAIT_USECS, 418}; 419 420/* 421 * Global: G_gather_secs 422 * Purpose: 423 * Time to wait for the ideal packet after receiving 424 * the first acceptable packet. 425 */ 426int G_gather_secs = GATHER_SECS; 427 428/* 429 * Global: G_initial_wait_secs 430 * Purpose: 431 * First timeout interval in seconds. 432 */ 433int G_initial_wait_secs = INITIAL_WAIT_SECS; 434 435/* 436 * Global: G_max_retries 437 * Purpose: 438 * Number of times to retry sending the packet. 439 */ 440int G_max_retries = MAX_RETRIES; 441 442/* 443 * Global: G_max_wait_secs 444 * Purpose: 445 * Maximum timeout interval. Timeouts timeout[i] are chosen as: 446 * i = 0: 447 * timeout[0] = G_initial_wait_secs; 448 * i > 0: 449 * timeout[i] = min(timeout[i - 1] * 2, G_max_wait_secs); 450 * If G_initial_wait_secs = 4, G_max_wait_secs = 16, the sequence is: 451 * 4, 8, 16, 16, ... 452 */ 453int G_max_wait_secs = MAX_WAIT_SECS; 454 455boolean_t G_must_broadcast; 456Boolean G_IPConfiguration_verbose; 457bootp_session_t * G_bootp_session = NULL; 458arp_session_t * G_arp_session = NULL; 459boolean_t G_router_arp = TRUE; 460int G_router_arp_wifi_lease_start_threshold_secs = (3600 * 24); /* 1 day */ 461boolean_t G_discover_and_publish_router_mac_address = TRUE; 462 463#define DHCPv6_ENABLED TRUE 464#define DHCPv6_STATEFUL_ENABLED TRUE 465 466boolean_t G_dhcpv6_enabled = DHCPv6_ENABLED; 467boolean_t G_dhcpv6_stateful_enabled = DHCPv6_STATEFUL_ENABLED; 468int G_dhcp_duid_type = kDHCPDUIDTypeLLT; 469 470const unsigned char G_rfc_magic[4] = RFC_OPTIONS_MAGIC; 471const struct in_addr G_ip_broadcast = { INADDR_BROADCAST }; 472const struct in_addr G_ip_zeroes = { 0 }; 473 474#define MIN_SHORT_WAKE_INTERVAL_SECS 60 475PRIVATE_EXTERN int G_min_short_wake_interval_secs = MIN_SHORT_WAKE_INTERVAL_SECS; 476#define MIN_WAKE_INTERVAL_SECS (60 * 15) 477PRIVATE_EXTERN int G_min_wake_interval_secs = MIN_WAKE_INTERVAL_SECS; 478#define WAKE_SKEW_SECS 30 479PRIVATE_EXTERN int G_wake_skew_secs = WAKE_SKEW_SECS; 480 481/* local variables */ 482static interface_list_t * S_interfaces = NULL; 483static CFBundleRef S_bundle = NULL; 484static CFRunLoopObserverRef S_observer = NULL; 485static boolean_t S_linklocal_needs_attention = FALSE; 486static IFStateList_t S_ifstate_list; 487static io_connect_t S_power_connection; 488static SCDynamicStoreRef S_scd_session = NULL; 489static CFStringRef S_setup_service_prefix = NULL; 490static CFStringRef S_state_interface_prefix = NULL; 491static char * S_computer_name = NULL; 492static CFStringRef S_computer_name_key = NULL; 493static CFStringRef S_hostnames_key = NULL; 494static int S_arp_probe_count = ARP_PROBE_COUNT; 495static int S_arp_gratuitous_count = ARP_GRATUITOUS_COUNT; 496static struct timeval S_arp_retry = { 497 ARP_RETRY_SECS, 498 ARP_RETRY_USECS 499}; 500static int S_arp_detect_count = ARP_DETECT_COUNT; 501static struct timeval S_arp_detect_retry = { 502 ARP_DETECT_RETRY_SECS, 503 ARP_DETECT_RETRY_USECS 504}; 505static struct timeval S_arp_resolve_retry = { 506 ARP_RESOLVE_RETRY_SECS, 507 ARP_RESOLVE_RETRY_USECS 508}; 509static int S_discover_router_mac_address_secs 510 = DISCOVER_ROUTER_MAC_ADDRESS_SECS; 511 512static int S_arp_conflict_retry = ARP_CONFLICT_RETRY_COUNT; 513static struct timeval S_arp_conflict_delay = { 514 ARP_CONFLICT_RETRY_DELAY_SECS, 515 ARP_CONFLICT_RETRY_DELAY_USECS 516}; 517 518static int S_defend_ip_address_interval_secs 519 = DEFEND_IP_ADDRESS_INTERVAL_SECS; 520static int S_defend_ip_address_count 521 = DEFEND_IP_ADDRESS_COUNT; 522 523 524static int S_dhcp_local_hostname_length_max = DHCP_LOCAL_HOSTNAME_LENGTH_MAX; 525 526static struct in_addr S_netboot_ip; 527static struct in_addr S_netboot_server_ip; 528static char S_netboot_ifname[IFNAMSIZ + 1]; 529 530static boolean_t S_awake = TRUE; 531#if ! TARGET_OS_EMBEDDED 532static boolean_t S_use_maintenance_wake = TRUE; 533static boolean_t S_wake_event_sent; 534#endif /* ! TARGET_OS_EMBEDDED */ 535static uint32_t S_wake_generation; 536static absolute_time_t S_wake_time; 537static boolean_t S_woke_from_hibernation; 538 539static boolean_t S_configure_ipv6 = TRUE; 540 541STATIC boolean_t S_active_during_sleep_needs_attention; 542 543#define PROP_SERVICEID CFSTR("ServiceID") 544 545/* 546 * forward declarations 547 */ 548static void 549S_add_dhcp_parameters(SCPreferencesRef prefs); 550 551static void 552configuration_changed(SCDynamicStoreRef session); 553 554static ipconfig_status_t 555config_method_event(ServiceRef service_p, IFEventID_t event, void * data); 556 557static ipconfig_status_t 558config_method_start(ServiceRef service_p, ipconfig_method_t method, 559 ipconfig_method_data_t * method_data); 560 561 562static ipconfig_status_t 563config_method_change(ServiceRef service_p, ipconfig_method_t method, 564 ipconfig_method_data_t * method_data, 565 boolean_t * needs_stop); 566 567 568static ipconfig_status_t 569config_method_stop(ServiceRef service_p); 570 571static ipconfig_status_t 572config_method_media(ServiceRef service_p, void * network_changed); 573 574static ipconfig_status_t 575config_method_bssid_changed(ServiceRef service_p); 576 577static ipconfig_status_t 578config_method_renew(ServiceRef service_p); 579 580static void 581service_publish_clear(ServiceRef service_p); 582 583static boolean_t 584all_services_ready(); 585 586static void 587S_linklocal_elect(CFArrayRef service_order); 588 589static CFArrayRef 590S_get_service_order(SCDynamicStoreRef session); 591 592static __inline__ IFStateRef 593service_ifstate(ServiceRef service_p) 594{ 595 return (service_p->ifstate); 596} 597 598static boolean_t 599S_get_plist_boolean_quiet(CFDictionaryRef plist, CFStringRef key, 600 boolean_t def); 601static int 602S_get_plist_int_quiet(CFDictionaryRef plist, CFStringRef key, 603 int def); 604 605static unsigned int 606S_get_service_rank(CFArrayRef arr, ServiceRef service_p); 607 608static IFStateRef 609IFStateList_ifstate_with_name(IFStateList_t * list, const char * ifname, 610 int * where); 611 612static IFStateRef 613IFStateListGetIFState(IFStateList_t * list, CFStringRef ifname, 614 int * where); 615static void 616IFStateFreeService(IFStateRef ifstate, ServiceRef service_p); 617 618static ServiceRef 619IFState_service_with_ip(IFStateRef ifstate, struct in_addr iaddr); 620 621static void 622IFState_set_ssid_bssid(IFStateRef ifstate, CFStringRef ssid, 623 const struct ether_addr * bssid); 624 625STATIC void 626IFStateSetActiveDuringSleepRequested(IFStateRef ifstate, boolean_t requested); 627 628STATIC void 629IFStateProcessActiveDuringSleep(IFStateRef ifstate); 630 631static void 632S_linklocal_start(ServiceRef parent_service_p, boolean_t allocate); 633 634static CFStringRef 635S_copy_ssid_bssid(CFStringRef ifname, struct ether_addr * ap_mac); 636 637static int 638S_remove_ip_address(const char * ifname, struct in_addr this_ip); 639 640STATIC ipconfig_status_t 641S_remove_service_with_id_str(const char * ifname, CFStringRef serviceID); 642 643static ipconfig_status_t 644method_info_from_dict(CFDictionaryRef dict, 645 ipconfig_method_t * ret_method, 646 ipconfig_method_data_t * * ret_method_data); 647static ipconfig_status_t 648method_info_from_ipv6_dict(CFDictionaryRef dict, 649 ipconfig_method_t * ret_method, 650 ipconfig_method_data_t * * ret_method_data); 651 652STATIC CFDictionaryRef 653ServiceIPv4CopyMergedDNS(ServiceRef service_p, dhcp_info_t * info_p); 654 655STATIC CFDictionaryRef 656ServiceIPv6CopyMergedDNS(ServiceRef service_p, dhcpv6_info_t * info_v6_p); 657 658STATIC void 659process_link_timer_expired(IFStateRef ifstate); 660 661STATIC bool 662my_CFStringToIPv6Address(CFStringRef str, struct in6_addr * ret_ip); 663 664static void 665service_list_event(dynarray_t * services_p, IFEventID_t event, void * data); 666 667PRIVATE_EXTERN const char * 668ipconfig_method_string(ipconfig_method_t m) 669{ 670 const char * str = "<unknown>"; 671 672 switch (m) { 673 case ipconfig_method_none_e: 674 str = "NONE"; 675 break; 676 case ipconfig_method_none_v4_e: 677 str = "NONE-V4"; 678 break; 679 case ipconfig_method_none_v6_e: 680 str = "NONE-V6"; 681 break; 682 case ipconfig_method_manual_e: 683 str = "MANUAL"; 684 break; 685 case ipconfig_method_bootp_e: 686 str = "BOOTP"; 687 break; 688 case ipconfig_method_dhcp_e: 689 str = "DHCP"; 690 break; 691 case ipconfig_method_inform_e: 692 str = "INFORM"; 693 break; 694 case ipconfig_method_linklocal_e: 695 str = "LINKLOCAL"; 696 break; 697 case ipconfig_method_failover_e: 698 str = "FAILOVER"; 699 break; 700 case ipconfig_method_manual_v6_e: 701 str = "MANUAL-V6"; 702 break; 703 case ipconfig_method_automatic_v6_e: 704 str = "AUTOMATIC-V6"; 705 break; 706 case ipconfig_method_rtadv_e: 707 str = "RTADV"; 708 break; 709 case ipconfig_method_stf_e: 710 str = "6TO4"; 711 break; 712 case ipconfig_method_linklocal_v6_e: 713 str = "LINKLOCAL-V6"; 714 break; 715 } 716 return (str); 717} 718 719/* 720 * Function: S_is_our_hardware_address 721 * 722 * Purpose: 723 * Returns whether the given hardware address is that of any of 724 * our attached network interfaces. 725 */ 726static boolean_t 727S_is_our_hardware_address(interface_t * ignored, 728 int hwtype, void * hwaddr, int hwlen) 729{ 730 int i; 731 732 for (i = 0; i < ifl_count(S_interfaces); i++) { 733 interface_t * if_p = ifl_at_index(S_interfaces, i); 734 int link_length = if_link_length(if_p); 735 736 if (hwlen != link_length) { 737 continue; 738 } 739 if (hwtype != if_link_arptype(if_p)) { 740 continue; 741 } 742 if (bcmp(hwaddr, if_link_address(if_p), link_length) == 0) { 743 return (TRUE); 744 } 745 } 746 return (FALSE); 747} 748 749#define kBSPAddress CFSTR("BonjourSleepProxyAddress") 750#define kBSPMACAddress kSCPropMACAddress 751#define kBSPRegisteredAddresses CFSTR("RegisteredAddresses") 752 753/* 754 * Function: S_copy_sleep_proxy_info 755 * Purpose: 756 * Copy the Bonjour Sleep Proxy Address information. 757 */ 758STATIC CFDictionaryRef 759S_copy_sleep_proxy_info(SCDynamicStoreRef store, CFStringRef ifname) 760{ 761 CFDictionaryRef info; 762 CFStringRef key; 763 764 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 765 kSCDynamicStoreDomainState, 766 ifname, 767 kBSPAddress); 768 info = SCDynamicStoreCopyValue(store, key); 769 CFRelease(key); 770 if (isA_CFDictionary(info) == NULL) { 771 my_CFRelease(&info); 772 } 773 return (info); 774} 775 776STATIC boolean_t 777S_is_sleep_proxy_hardware_address(SCDynamicStoreRef session, 778 IFStateRef ifstate, 779 void * hwaddr, int hw_len) 780{ 781 /* check if the address belongs to any of the known sleep proxies */ 782 boolean_t found = FALSE; 783 CFDictionaryRef info; 784 785 info = S_copy_sleep_proxy_info(session, ifstate->ifname); 786 if (info != NULL) { 787 CFStringRef sp_mac_cf; 788 789 sp_mac_cf = CFDictionaryGetValue(info, kBSPMACAddress); 790 if (isA_CFString(sp_mac_cf) != NULL) { 791 int len; 792 void * sp_mac; 793 794 sp_mac = bytesFromColonHexString(sp_mac_cf, &len); 795 if (sp_mac != NULL) { 796 if (len == hw_len) { 797 if (bcmp(sp_mac, hwaddr, len) == 0) { 798 found = TRUE; 799 } 800 } 801 free(sp_mac); 802 } 803 } 804 CFRelease(info); 805 } 806 return (found); 807} 808 809/* 810 * Function: S_process_neighbor_adverts 811 * Purpose: 812 * Process the list of IPv6 addresses we registered with a sleep proxy. 813 * For each address, check whether it is in the list of addresses 814 * currently assigned to the interface. If it is, then send a 815 * Neighbor Advertisement packet. 816 * 817 * The list of IPv6 addresses is copied at wake, and tossed at sleep. 818 * If the list is more than 60 seconds old, also toss it to avoid needing 819 * to traverse it if we happen to end up with an address in there that's 820 * never going to get assigned (e.g. temporary address, or we switched 821 * networks). 822 */ 823STATIC void 824S_process_neighbor_adverts(IFStateRef ifstate, inet6_addrlist_t * addr_list_p) 825{ 826 CFIndex count; 827 absolute_time_t current_time; 828 int i; 829 interface_t * if_p; 830 int sockfd = -1; 831 832 if (ifstate->neighbor_advert_list == NULL) { 833 return; 834 } 835 836#define kProcessNeighborAdvertExpirationTimeSecs 60 837 current_time = timer_current_secs(); 838 if ((current_time - S_wake_time) 839 > kProcessNeighborAdvertExpirationTimeSecs) { 840 my_log(LOG_DEBUG, 841 "%@: tossing neighbor advert list (%ld - %ld) > (%d)", 842 ifstate->ifname, 843 current_time, 844 S_wake_time, 845 kProcessNeighborAdvertExpirationTimeSecs); 846 /* information is stale, toss it */ 847 my_CFRelease(&ifstate->neighbor_advert_list); 848 return; 849 } 850 if_p = ifstate->if_p; 851 count = CFArrayGetCount(ifstate->neighbor_advert_list); 852 for (i = 0; i < count; ) { 853 struct in6_addr address; 854 CFStringRef address_cf; 855 int error; 856 boolean_t remove = FALSE; 857 858 address_cf = (CFStringRef) 859 CFArrayGetValueAtIndex(ifstate->neighbor_advert_list, i); 860 if (my_CFStringToIPv6Address(address_cf, &address) == FALSE) { 861 /* failed to convert, remove bogus value */ 862 my_log(LOG_ERR, "%@: bogus address value %@", 863 ifstate->ifname, address_cf); 864 remove = TRUE; 865 } 866 else if (inet6_addrlist_in6_addr_is_ready(addr_list_p, 867 &address) == FALSE) { 868 /* address not assigned or is not ready */ 869 my_log(LOG_ERR, "%@: address %@ not present/ready", 870 ifstate->ifname, address_cf); 871 remove = FALSE; 872 } 873 else { 874 /* address ready, send neighbor advert and remove from list */ 875 remove = TRUE; 876 if (sockfd < 0) { 877 sockfd = ICMPv6SocketOpen(FALSE); 878 if (sockfd < 0) { 879 my_log_fl(LOG_ERR, "can't open socket, %s", 880 strerror(errno)); 881 break; 882 } 883 } 884 error 885 = ICMPv6SocketSendNeighborAdvertisement(sockfd, 886 if_link_index(if_p), 887 if_link_address(if_p), 888 if_link_length(if_p), 889 &address); 890 error = 0; 891 if (error != 0) { 892 my_log(LOG_ERR, 893 "%s: failed to send neighbor advertisement, %s", 894 if_name(if_p), strerror(error)); 895 } 896 else if (G_IPConfiguration_verbose) { 897 char ntopbuf[INET6_ADDRSTRLEN]; 898 899 my_log(LOG_DEBUG, 900 "%s: sent neighbor advertisement for %s", 901 if_name(if_p), 902 inet_ntop(AF_INET6, &address, ntopbuf, sizeof(ntopbuf))); 903 } 904 } 905 if (remove) { 906 CFArrayRemoveValueAtIndex(ifstate->neighbor_advert_list, i); 907 count--; 908 } 909 else { 910 /* skip to next value */ 911 i++; 912 } 913 } 914 if (CFArrayGetCount(ifstate->neighbor_advert_list) == 0) { 915 /* list is empty, toss it */ 916 my_CFRelease(&ifstate->neighbor_advert_list); 917 } 918 919 if (sockfd >= 0) { 920 close(sockfd); 921 } 922 return; 923} 924 925STATIC CFMutableArrayRef 926S_copy_neighbor_advert_list(SCDynamicStoreRef store, CFStringRef ifname) 927{ 928 CFDictionaryRef info; 929 CFArrayRef list; 930 CFMutableArrayRef ret = NULL; 931 932 info = S_copy_sleep_proxy_info(store, ifname); 933 if (info != NULL) { 934 list = CFDictionaryGetValue(info, kBSPRegisteredAddresses); 935 if (isA_CFArray(list) != NULL) { 936 if (G_IPConfiguration_verbose) { 937 my_log(LOG_DEBUG, "%@: Sleep Proxy Addresses = %@", 938 ifname, list); 939 } 940 ret = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(list), list); 941 } 942 CFRelease(info); 943 } 944 return (ret); 945} 946 947/** 948 ** Computer Name handling routines 949 **/ 950 951PRIVATE_EXTERN char * 952computer_name() 953{ 954 return (S_computer_name); 955} 956 957/* 958 * Try to shorten the length of the string by replacing certain 959 * product names. If still not short enough, eliminate -'s. 960 * If still not short enough, remove enough of the middle part of 961 * the remaining string to make it 'desired_length'. 962 */ 963static CFStringRef 964myCFStringCopyShortenedString(CFStringRef computer_name, int desired_length) 965{ 966 CFMutableStringRef short_name; 967 CFIndex len, delete_len; 968 969#define MINIMUM_SHORTENED_STRING_LENGTH 3 // Min 3 chars <first part>-<last part> 970 971 972 if (computer_name == NULL 973 || desired_length < MINIMUM_SHORTENED_STRING_LENGTH) { 974 return NULL; 975 } 976 short_name = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, computer_name); 977 978 /* 979 * shorten commonly used long names like MacBook-Pro, MacBook-Air 980 */ 981 CFStringFindAndReplace(short_name, CFSTR("macbook-air"), CFSTR("Air"), CFRangeMake(0, CFStringGetLength(computer_name)), kCFCompareCaseInsensitive); 982 CFStringFindAndReplace(short_name, CFSTR("macbook-pro"), CFSTR("MBP"), CFRangeMake(0, CFStringGetLength(computer_name)), kCFCompareCaseInsensitive); 983 CFStringFindAndReplace(short_name, CFSTR("mac-mini"), CFSTR("Mini"), CFRangeMake(0, CFStringGetLength(computer_name)), kCFCompareCaseInsensitive); 984 CFStringFindAndReplace(short_name, CFSTR("mac-pro"), CFSTR("Pro"), CFRangeMake(0, CFStringGetLength(computer_name)), kCFCompareCaseInsensitive); 985 986 // recompute the new string length 987 len = CFStringGetLength(short_name); 988 if (len <= desired_length) { 989 /* shrinking long names worked */ 990 return short_name; 991 } 992 993 CFStringFindAndReplace(short_name, CFSTR("-"), CFSTR(""), CFRangeMake(0, len-1), kCFCompareCaseInsensitive); 994 // recompute the new string length 995 len = CFStringGetLength(short_name); 996 997 if (len <= desired_length) { 998 /* computer name already short due to removal of '-'*/ 999 return short_name; 1000 } 1001 1002 delete_len = len - desired_length; 1003 // last option: eliminate the middle string, keep first and last part of the string 1004 CFStringDelete(short_name, 1005 CFRangeMake(desired_length / 2, delete_len)); 1006 1007 return short_name; 1008 1009} 1010 1011static void 1012computer_name_update(SCDynamicStoreRef session) 1013{ 1014 char buf[256]; 1015 CFStringEncoding encoding; 1016 CFStringRef name; 1017 1018 if (session == NULL) 1019 return; 1020 1021 if (S_computer_name) { 1022 free(S_computer_name); 1023 S_computer_name = NULL; 1024 } 1025 1026 name = SCDynamicStoreCopyComputerName(session, &encoding); 1027 if (name == NULL) { 1028 goto done; 1029 } 1030 if (_SC_CFStringIsValidDNSName(name) == FALSE) { 1031 my_CFRelease(&name); 1032 name = SCDynamicStoreCopyLocalHostName(session); 1033 if (name == NULL) { 1034 goto done; 1035 } 1036 if (_SC_CFStringIsValidDNSName(name) == FALSE) { 1037 goto done; 1038 } 1039 if (CFStringGetLength(name) > S_dhcp_local_hostname_length_max) { 1040 /* don't exceed the maximum */ 1041 CFStringRef short_name = myCFStringCopyShortenedString(name, S_dhcp_local_hostname_length_max); 1042 if (short_name == NULL) { 1043 goto done; 1044 } 1045 my_CFRelease(&name); 1046 name = short_name; 1047 } 1048 } 1049 if (CFStringGetCString(name, buf, sizeof(buf), 1050 kCFStringEncodingASCII) == FALSE) { 1051 goto done; 1052 } 1053 S_computer_name = strdup(buf); 1054 1055 done: 1056 my_CFRelease(&name); 1057 return; 1058} 1059 1060/** 1061 ** ARP routine 1062 **/ 1063 1064static void 1065service_resolve_router_complete(void * arg1, void * arg2, 1066 const arp_result_t * result) 1067{ 1068 service_resolve_router_callback_t * callback_func; 1069 interface_t * if_p; 1070 ServiceRef service_p; 1071 router_arp_status_t status; 1072 1073 service_p = (ServiceRef)arg1; 1074 callback_func = (service_resolve_router_callback_t *)arg2; 1075 if_p = service_interface(service_p); 1076 if (result->error) { 1077 my_log(LOG_ERR, "service_resolve_router_complete %s: ARP failed, %s", 1078 if_name(if_p), 1079 arp_client_errmsg(result->client)); 1080 status = router_arp_status_failed_e; 1081 } 1082 else if (result->in_use) { 1083 /* grab the latest router hardware address */ 1084 bcopy(result->addr.target_hardware, service_p->u.v4.router.hwaddr, 1085 if_link_length(if_p)); 1086 service_router_set_all_valid(service_p); 1087 my_log(LOG_DEBUG, "service_resolve_router_complete %s: ARP " 1088 IP_FORMAT ": response received", if_name(if_p), 1089 IP_LIST(&service_p->u.v4.router.iaddr)); 1090 status = router_arp_status_success_e; 1091 } 1092 else { 1093 status = router_arp_status_no_response_e; 1094 my_log(LOG_DEBUG, "service_resolve_router_complete %s: ARP router " 1095 IP_FORMAT ": no response", if_name(if_p), 1096 IP_LIST(&service_p->u.v4.router.iaddr)); 1097 } 1098 (*callback_func)(service_p, status); 1099 return; 1100} 1101 1102PRIVATE_EXTERN boolean_t 1103service_resolve_router(ServiceRef service_p, arp_client_t * arp, 1104 service_resolve_router_callback_t * callback_func, 1105 struct in_addr our_ip) 1106{ 1107 interface_t * if_p = service_interface(service_p); 1108 struct in_addr router_ip; 1109 1110 if (G_discover_and_publish_router_mac_address == FALSE) { 1111 /* don't bother */ 1112 return (FALSE); 1113 } 1114 1115 service_router_clear_arp_verified(service_p); 1116 if (service_router_is_iaddr_valid(service_p) == 0) { 1117 my_log(LOG_NOTICE, 1118 "service_resolve_router %s: IP address missing", if_name(if_p)); 1119 return (FALSE); 1120 } 1121 router_ip = service_router_iaddr(service_p); 1122 my_log(LOG_DEBUG, "service_resolve_router %s: sender " IP_FORMAT 1123 " target " IP_FORMAT " started", 1124 if_name(if_p), IP_LIST(&our_ip), IP_LIST(&router_ip)); 1125 arp_client_resolve(arp, service_resolve_router_complete, 1126 service_p, callback_func, our_ip, router_ip, 1127 S_discover_router_mac_address_secs); 1128 return (TRUE); 1129} 1130 1131PRIVATE_EXTERN boolean_t 1132service_populate_router_arpinfo(ServiceRef service_p, 1133 arp_address_info_t * info_p) 1134{ 1135 interface_t * if_p = service_interface(service_p); 1136 struct in_addr router_ip; 1137 1138 if (G_discover_and_publish_router_mac_address == FALSE) { 1139 /* don't bother */ 1140 return (FALSE); 1141 } 1142 1143 service_router_clear_arp_verified(service_p); 1144 1145 if (service_router_is_iaddr_valid(service_p) == 0) { 1146 my_log(LOG_DEBUG, 1147 "service_populate_router_arpinfo %s: " 1148 "Router IP address missing", 1149 if_name(if_p)); 1150 return (FALSE); 1151 } 1152 1153 router_ip = service_router_iaddr(service_p); 1154 1155 my_log(LOG_DEBUG, "service_populate_router_arpinfo %s: " 1156 "found gateway " IP_FORMAT, 1157 if_name(if_p), IP_LIST(&router_ip)); 1158 1159 1160 info_p->target_ip = router_ip; 1161 bcopy(service_router_hwaddr(service_p), info_p->target_hardware, 1162 service_router_hwaddr_size(service_p)); 1163 1164 return (TRUE); 1165} 1166 1167 1168PRIVATE_EXTERN boolean_t 1169service_update_router_address(ServiceRef service_p, 1170 dhcpol_t * options, struct in_addr our_ip) 1171{ 1172 struct in_addr * router_p; 1173 1174 router_p = dhcp_get_router_from_options(options, our_ip); 1175 if (router_p == NULL) { 1176 goto failed; 1177 } 1178 if (service_router_all_valid(service_p) 1179 && router_p->s_addr == service_router_iaddr(service_p).s_addr) { 1180 /* router is the same, no need to update */ 1181 return (FALSE); 1182 } 1183 service_router_clear(service_p); 1184 service_router_set_iaddr(service_p, *router_p); 1185 service_router_set_iaddr_valid(service_p); 1186 return (TRUE); 1187 1188 failed: 1189 service_router_clear(service_p); 1190 return (FALSE); 1191} 1192 1193#define STARTUP_KEY CFSTR("Plugin:IPConfiguration") 1194 1195static __inline__ void 1196unblock_startup(SCDynamicStoreRef session) 1197{ 1198 (void)SCDynamicStoreSetValue(session, STARTUP_KEY, STARTUP_KEY); 1199} 1200 1201/** 1202 ** Active During Sleep (ADS) routines 1203 **/ 1204INLINE CFStringRef 1205ActiveDuringSleepRequestedKeyCopy(CFStringRef ifn_cf) 1206{ 1207 return (SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 1208 kSCDynamicStoreDomainState, 1209 ifn_cf, 1210 kSCEntNetInterfaceActiveDuringSleepRequested)); 1211} 1212 1213STATIC void 1214ActiveDuringSleepRequestedKeyChanged(SCDynamicStoreRef store, 1215 CFStringRef cache_key) 1216{ 1217 boolean_t ads_requested; 1218 CFDictionaryRef dict; 1219 CFStringRef ifname; 1220 IFStateRef ifstate; 1221 1222 if (CFStringHasPrefix(cache_key, S_state_interface_prefix) == FALSE) { 1223 return; 1224 } 1225 1226 /* State:/Network/Interface/<ifname>/ActiveDuringSleepRequested */ 1227 ifname = my_CFStringCopyComponent(cache_key, CFSTR("/"), 3); 1228 if (ifname == NULL) { 1229 return; 1230 } 1231 ifstate = IFStateListGetIFState(&S_ifstate_list, ifname, NULL); 1232 my_CFRelease(&ifname); 1233 if (ifstate != NULL) { 1234 dict = SCDynamicStoreCopyValue(store, cache_key); 1235 if (dict != NULL) { 1236 ads_requested = TRUE; 1237 CFRelease(dict); 1238 } 1239 else { 1240 ads_requested = FALSE; 1241 } 1242 IFStateSetActiveDuringSleepRequested(ifstate, ads_requested); 1243 } 1244 return; 1245} 1246 1247STATIC void 1248ActiveDuringSleepProcess(IFStateList_t * list) 1249{ 1250 int i; 1251 int if_count; 1252 1253 if_count = dynarray_count(list); 1254 for (i = 0; i < if_count; i++) { 1255 IFStateRef ifstate = dynarray_element(list, i); 1256 1257 IFStateProcessActiveDuringSleep(ifstate); 1258 } 1259 return; 1260} 1261 1262#define WAKE_ID_PREFIX "com.apple.networking.IPConfiguration" 1263 1264STATIC void 1265CleanupWakeEvents(void) 1266{ 1267 CFArrayRef events; 1268 CFIndex count; 1269 int i; 1270 1271 events = IOPMCopyScheduledPowerEvents(); 1272 if (events == NULL) { 1273 return; 1274 } 1275 count = CFArrayGetCount(events); 1276 for (i = 0; i < count; i++) { 1277 CFDictionaryRef event = CFArrayGetValueAtIndex(events, i); 1278 CFStringRef wake_id; 1279 1280 wake_id = CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventAppNameKey)); 1281 if (CFStringHasPrefix(wake_id, CFSTR(WAKE_ID_PREFIX))) { 1282 CFDateRef wake_time; 1283 1284 my_log_fl(LOG_DEBUG, "IOPMCancelScheduledPowerEvent(%@)", wake_id); 1285 wake_time 1286 = CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTimeKey)); 1287 IOPMCancelScheduledPowerEvent(wake_time, wake_id, 1288 CFSTR(kIOPMAutoWake)); 1289 } 1290 } 1291 CFRelease(events); 1292 return; 1293} 1294 1295/** 1296 ** Service, IFState routines 1297 **/ 1298static void 1299ServiceFree(void * arg) 1300{ 1301 IFStateRef ifstate; 1302 ServiceRef service_p = (ServiceRef)arg; 1303 1304 if (G_IPConfiguration_verbose) { 1305 my_log(LOG_DEBUG, "ServiceFree(%@) %s", 1306 service_p->serviceID, ipconfig_method_string(service_p->method)); 1307 } 1308 ifstate = service_ifstate(service_p); 1309 if (ifstate != NULL && ifstate->linklocal_service_p == service_p) { 1310 ifstate->linklocal_service_p = NULL; 1311 } 1312 config_method_stop(service_p); 1313 service_publish_clear(service_p); 1314#if ! TARGET_OS_EMBEDDED 1315 ServiceRemoveAddressConflict(service_p); 1316#endif /* ! TARGET_OS_EMBEDDED */ 1317 my_CFRelease(&service_p->serviceID); 1318 my_CFRelease(&service_p->parent_serviceID); 1319 my_CFRelease(&service_p->child_serviceID); 1320 if (service_p->pid_source != NULL) { 1321 CFStringRef serviceID; 1322 1323 serviceID = (CFStringRef)dispatch_get_context(service_p->pid_source); 1324 CFRelease(serviceID); 1325 dispatch_source_cancel(service_p->pid_source); 1326 dispatch_release(service_p->pid_source); 1327 service_p->pid_source = NULL; 1328 } 1329 free(service_p); 1330 return; 1331} 1332 1333static ServiceRef 1334ServiceCreate(IFStateRef ifstate, CFStringRef serviceID, 1335 ipconfig_method_t method, 1336 ipconfig_method_data_t * method_data, 1337 ServiceRef parent_service_p, ipconfig_status_t * status_p) 1338{ 1339 ServiceRef service_p; 1340 ipconfig_status_t status = ipconfig_status_success_e; 1341 1342 if (method == ipconfig_method_linklocal_e 1343 && ifstate->linklocal_service_p != NULL) { 1344 IFStateFreeService(ifstate, 1345 ifstate->linklocal_service_p); 1346 /* side-effect: ifstate->linklocal_service_p = NULL */ 1347 } 1348 service_p = (ServiceRef)malloc(sizeof(*service_p)); 1349 if (service_p == NULL) { 1350 status = ipconfig_status_allocation_failed_e; 1351 goto failed; 1352 } 1353 bzero(service_p, sizeof(*service_p)); 1354 service_p->method = method; 1355 service_p->ifstate = ifstate; 1356 if (serviceID != NULL) { 1357 service_p->serviceID = (void *)CFRetain(serviceID); 1358 } 1359 else { 1360 service_p->serviceID = (void *) 1361 CFStringCreateWithFormat(NULL, NULL, 1362 CFSTR("%s-%s"), 1363 ipconfig_method_string(method), 1364 if_name(ifstate->if_p)); 1365 } 1366 if (parent_service_p != NULL) { 1367 service_p->parent_serviceID 1368 = (void *)CFRetain(parent_service_p->serviceID); 1369 } 1370 status = config_method_start(service_p, method, method_data); 1371 if (status != ipconfig_status_success_e) { 1372 goto failed; 1373 } 1374 if (parent_service_p != NULL) { 1375 my_CFRelease(&parent_service_p->child_serviceID); 1376 parent_service_p->child_serviceID 1377 = (void *)CFRetain(service_p->serviceID); 1378 } 1379 1380 /* keep track of which service is the linklocal service */ 1381 if (service_p->method == ipconfig_method_linklocal_e) { 1382 ifstate->linklocal_service_p = service_p; 1383 } 1384 *status_p = status; 1385 return (service_p); 1386 1387 failed: 1388 if (service_p != NULL) { 1389 my_CFRelease(&service_p->serviceID); 1390 my_CFRelease(&service_p->parent_serviceID); 1391 free(service_p); 1392 } 1393 *status_p = status; 1394 return (NULL); 1395} 1396 1397static void 1398ServiceHandleProcessExit(dispatch_source_t source) 1399{ 1400 pid_t pid; 1401 CFStringRef serviceID; 1402 ipconfig_status_t status; 1403 1404 pid = (pid_t)dispatch_source_get_handle(source); 1405 my_log(LOG_DEBUG, "IPConfiguration: pid %d exited", pid); 1406 serviceID = (CFStringRef)dispatch_get_context(source); 1407 status = S_remove_service_with_id_str(NULL, serviceID); 1408 if (status != ipconfig_status_success_e) { 1409 my_log(LOG_ERR, 1410 "IPConfiguration: failed to stop service %@, %s", 1411 serviceID, ipconfig_status_string(status)); 1412 } 1413 return; 1414} 1415 1416static CFRunLoopRef S_plugin_runloop; 1417 1418static void 1419ServiceProcessExited(dispatch_source_t source) 1420{ 1421 /* handle the source on our runloop to avoid locking issues */ 1422 CFRunLoopPerformBlock(S_plugin_runloop, 1423 kCFRunLoopDefaultMode, 1424 ^{ ServiceHandleProcessExit(source); }); 1425 CFRunLoopWakeUp(S_plugin_runloop); 1426 return; 1427} 1428 1429static void 1430ServiceMonitorPID(ServiceRef service_p, pid_t pid) 1431{ 1432 dispatch_source_t source; 1433 1434 if (S_plugin_runloop == NULL) { 1435 S_plugin_runloop = CFRunLoopGetCurrent(); 1436 } 1437 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, 1438 DISPATCH_PROC_EXIT, 1439 dispatch_get_main_queue()); 1440 if (source == NULL) { 1441 my_log(LOG_ERR, "IPConfiguration: dispatch_source_create failed"); 1442 return; 1443 } 1444 CFRetain(service_p->serviceID); 1445 dispatch_set_context(source, (void *)service_p->serviceID); 1446 dispatch_source_set_event_handler(source, 1447 ^{ ServiceProcessExited(source); }); 1448 dispatch_resume(source); 1449 service_p->pid_source = source; 1450 return; 1451} 1452 1453static ServiceRef 1454IFStateGetServiceWithID(IFStateRef ifstate, CFStringRef serviceID, 1455 boolean_t is_ipv4) 1456{ 1457 int i; 1458 dynarray_t * list; 1459 1460 if (is_ipv4) { 1461 list = &ifstate->services; 1462 } 1463 else { 1464 list = &ifstate->services_v6; 1465 } 1466 for (i = 0; i < dynarray_count(list); i++) { 1467 ServiceRef service_p = dynarray_element(list, i); 1468 1469 if (CFEqual(serviceID, service_p->serviceID)) { 1470 return (service_p); 1471 } 1472 } 1473 return (NULL); 1474} 1475 1476 1477static ServiceRef 1478IFState_service_with_ip(IFStateRef ifstate, struct in_addr iaddr) 1479{ 1480 int j; 1481 1482 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 1483 ServiceRef service_p = dynarray_element(&ifstate->services, j); 1484 1485 if (service_p->u.v4.info.addr.s_addr == iaddr.s_addr) { 1486 return (service_p); 1487 } 1488 } 1489 return (NULL); 1490} 1491 1492/* 1493 * Function: IFStateGetServiceMatchingIPv4Method 1494 * Purpose: 1495 * Find a service that "matches" the given requested IPv4 method. A service 1496 * "matches" if the method types are not manual (i.e. BOOTP, DHCP), 1497 * or the method types are manual (Manual, Inform, Failover), and the 1498 * requested IP address matches. 1499 * 1500 * If the parameter "just_dynamic" is TRUE, only match any dynamic 1501 * service, otherwise match all services. 1502 * 1503 */ 1504static ServiceRef 1505IFStateGetServiceMatchingIPv4Method(IFStateRef ifstate, 1506 ipconfig_method_t method, 1507 ipconfig_method_data_t * method_data, 1508 boolean_t just_dynamic) 1509{ 1510 int i; 1511 boolean_t is_dhcp_or_bootp = FALSE; 1512 boolean_t is_manual; 1513 1514 is_manual = ipconfig_method_is_manual(method); 1515 if (is_manual == FALSE) { 1516 is_dhcp_or_bootp = ipconfig_method_is_dhcp_or_bootp(method); 1517 } 1518 for (i = 0; i < dynarray_count(&ifstate->services); i++) { 1519 ServiceRef service_p = dynarray_element(&ifstate->services, i); 1520 1521 if (just_dynamic && service_p->is_dynamic == FALSE) { 1522 continue; 1523 } 1524 if (is_manual) { 1525 if (ipconfig_method_is_manual(service_p->method) 1526 && (method_data->manual.addr.s_addr 1527 == service_requested_ip_addr(service_p).s_addr)) { 1528 return (service_p); 1529 } 1530 } 1531 else if (is_dhcp_or_bootp 1532 && ipconfig_method_is_dhcp_or_bootp(service_p->method)) { 1533 return (service_p); 1534 } 1535 else if (service_p->method == method) { 1536 return (service_p); 1537 } 1538 } 1539 return (NULL); 1540} 1541 1542/* 1543 * Function: IFStateGetServiceMatchingIPv6Method 1544 * Purpose: 1545 * Find a service that "matches" the given requested method. A service 1546 * "matches" if the method types are the same, and for manual method, 1547 * the IPv6 addresses are the same. 1548 * 1549 * If the parameter "just_dynamic" is TRUE, only match any dynamic 1550 * service, otherwise match all services. 1551 * 1552 */ 1553static ServiceRef 1554IFStateGetServiceMatchingIPv6Method(IFStateRef ifstate, 1555 ipconfig_method_t method, 1556 ipconfig_method_data_t * method_data, 1557 boolean_t just_dynamic) 1558{ 1559 int i; 1560 1561 for (i = 0; i < dynarray_count(&ifstate->services_v6); i++) { 1562 ServiceRef service_p = dynarray_element(&ifstate->services_v6, i); 1563 ServiceIPv6Ref v6_p; 1564 1565 if (just_dynamic && service_p->is_dynamic == FALSE) { 1566 continue; 1567 } 1568 if (service_p->method != method) { 1569 continue; 1570 } 1571 if (method != ipconfig_method_manual_v6_e) { 1572 return (service_p); 1573 } 1574 v6_p = (ServiceIPv6Ref)service_p; 1575 if (IN6_ARE_ADDR_EQUAL(&method_data->manual_v6.addr, 1576 &v6_p->requested_ip.addr)) { 1577 return (service_p); 1578 } 1579 } 1580 return (NULL); 1581} 1582 1583/* 1584 * Function: IFStateGetServiceMatchingMethod 1585 * Purpose: 1586 * Find a service that "matches" the given requested method. 1587 */ 1588static ServiceRef 1589IFStateGetServiceMatchingMethod(IFStateRef ifstate, 1590 ipconfig_method_t method, 1591 ipconfig_method_data_t * method_data, 1592 boolean_t just_dynamic) 1593{ 1594 if (ipconfig_method_is_v4(method)) { 1595 return (IFStateGetServiceMatchingIPv4Method(ifstate, method, 1596 method_data, 1597 just_dynamic)); 1598 } 1599 return (IFStateGetServiceMatchingIPv6Method(ifstate, method, 1600 method_data, 1601 just_dynamic)); 1602} 1603 1604static ServiceRef 1605IFStateGetServiceWithIPv4Method(IFStateRef ifstate, 1606 ipconfig_method_t method, 1607 ipconfig_method_data_t * method_data, 1608 boolean_t just_dynamic) 1609{ 1610 int j; 1611 boolean_t is_manual; 1612 1613 is_manual = ipconfig_method_is_manual(method); 1614 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 1615 ServiceRef service_p = dynarray_element(&ifstate->services, j); 1616 1617 if (just_dynamic && service_p->is_dynamic == FALSE) { 1618 continue; 1619 } 1620 if (method == service_p->method) { 1621 if (is_manual == FALSE 1622 || (method_data->manual.addr.s_addr 1623 == service_requested_ip_addr(service_p).s_addr)) { 1624 return (service_p); 1625 } 1626 } 1627 } 1628 return (NULL); 1629} 1630 1631static __inline__ ServiceRef 1632IFStateGetServiceWithIPv6Method(IFStateRef ifstate, 1633 ipconfig_method_t method, 1634 ipconfig_method_data_t * method_data, 1635 boolean_t just_dynamic) 1636{ 1637 /* IFStateGetServiceMatchingIPv6Method is already an exact match */ 1638 return (IFStateGetServiceMatchingIPv6Method(ifstate, method, 1639 method_data, 1640 just_dynamic)); 1641} 1642 1643/* 1644 * Function: IFStateGetServiceWithMethod 1645 * Purpose: 1646 * Find a service with the given method and method args. 1647 * 1648 * If the parameter "just_dynamic" is TRUE, only match any dynamic 1649 * service, otherwise match all services. 1650 * 1651 */ 1652static ServiceRef 1653IFStateGetServiceWithMethod(IFStateRef ifstate, 1654 ipconfig_method_t method, 1655 ipconfig_method_data_t * method_data, 1656 boolean_t just_dynamic) 1657{ 1658 if (ipconfig_method_is_v4(method)) { 1659 return (IFStateGetServiceWithIPv4Method(ifstate, method, 1660 method_data, 1661 just_dynamic)); 1662 } 1663 return (IFStateGetServiceWithIPv6Method(ifstate, method, 1664 method_data, 1665 just_dynamic)); 1666} 1667 1668static void 1669S_FreeNonDynamicServices(dynarray_t * services_p) 1670{ 1671 int count; 1672 int i; 1673 1674 count = dynarray_count(services_p); 1675 for (i = 0; i < count; ) { 1676 ServiceRef service_p = dynarray_element(services_p, i); 1677 1678 if (service_p->is_dynamic) { 1679 i++; 1680 continue; 1681 } 1682 dynarray_free_element(services_p, i); 1683 count--; 1684 } 1685 return; 1686} 1687 1688static void 1689IFStateFreeIPv4Services(IFStateRef ifstate, boolean_t all) 1690{ 1691 if (all) { 1692 dynarray_free(&ifstate->services); 1693 } 1694 else { 1695 S_FreeNonDynamicServices(&ifstate->services); 1696 } 1697 ifstate->startup_ready = TRUE; 1698 if (dynarray_count(&ifstate->services) == 0 1699 && if_ift_type(ifstate->if_p) != IFT_STF) { 1700 inet_detach_interface(if_name(ifstate->if_p)); 1701 } 1702 return; 1703} 1704 1705static void 1706IFStateFreeIPv6Services(IFStateRef ifstate, boolean_t all) 1707{ 1708 if (all) { 1709 dynarray_free(&ifstate->services_v6); 1710 } 1711 else { 1712 S_FreeNonDynamicServices(&ifstate->services_v6); 1713 } 1714 if (dynarray_count(&ifstate->services_v6) == 0) { 1715 (void)inet6_linklocal_stop(if_name(ifstate->if_p)); 1716 inet6_detach_interface(if_name(ifstate->if_p)); 1717 } 1718 return; 1719} 1720 1721static void 1722IFStateFreeServiceWithID(IFStateRef ifstate, CFStringRef serviceID, 1723 boolean_t is_ipv4) 1724{ 1725 int i; 1726 dynarray_t * list; 1727 1728 if (is_ipv4) { 1729 list = &ifstate->services; 1730 } 1731 else { 1732 list = &ifstate->services_v6; 1733 } 1734 for (i = 0; i < dynarray_count(list); i++) { 1735 ServiceRef service_p = dynarray_element(list, i); 1736 1737 if (CFEqual(serviceID, service_p->serviceID)) { 1738 dynarray_free_element(list, i); 1739 return; 1740 } 1741 } 1742 return; 1743} 1744 1745static void 1746IFStateFreeService(IFStateRef ifstate, ServiceRef service_p) 1747{ 1748 IFStateFreeServiceWithID(ifstate, service_p->serviceID, 1749 ipconfig_method_is_v4(service_p->method)); 1750 return; 1751} 1752 1753static ipconfig_status_t 1754IFState_service_add(IFStateRef ifstate, CFStringRef serviceID, 1755 ipconfig_method_t method, void * method_data, 1756 ServiceRef parent_service_p, ServiceRef * ret_service_p) 1757{ 1758 interface_t * if_p = ifstate->if_p; 1759 ServiceRef service_p = NULL; 1760 ipconfig_status_t status = ipconfig_status_success_e; 1761 boolean_t started_v6_linklocal = FALSE; 1762 1763 if (ipconfig_method_is_v4(method)) { 1764 /* attach IP */ 1765 inet_attach_interface(if_name(if_p)); 1766 } 1767 else { 1768 int ift_type = if_ift_type(if_p); 1769 1770 /* attach IPv6 */ 1771 inet6_attach_interface(if_name(if_p)); 1772 1773 if (ift_type != IFT_LOOP && ift_type != IFT_STF) { 1774 link_status_t link = if_get_link_status(if_p); 1775 1776 /* make sure ND6_IFF_PERFORMNUD is set correctly */ 1777 (void)inet6_set_perform_nud(if_name(if_p), 1778 !ifstate->disable_perform_nud); 1779 1780 /* start IPv6 Link Local */ 1781 if (link.valid == FALSE || link.active) { 1782 (void)inet6_linklocal_start(if_name(if_p), !if_is_awdl(if_p)); 1783 started_v6_linklocal = TRUE; 1784 } 1785 } 1786 } 1787 /* try to configure the service */ 1788 service_p = ServiceCreate(ifstate, serviceID, method, 1789 method_data, 1790 parent_service_p, &status); 1791 if (service_p == NULL) { 1792 my_log(LOG_DEBUG, "status from %s was %s", 1793 ipconfig_method_string(method), 1794 ipconfig_status_string(status)); 1795 if (ipconfig_method_is_v4(method)) { 1796 if (dynarray_count(&ifstate->services) == 0) { 1797 /* no services configured, detach IP again */ 1798 ifstate->startup_ready = TRUE; 1799 inet_detach_interface(if_name(if_p)); 1800 } 1801 } 1802 else { 1803 if (dynarray_count(&ifstate->services_v6) == 0) { 1804 if (started_v6_linklocal) { 1805 (void)inet6_linklocal_stop(if_name(if_p)); 1806 } 1807 inet6_detach_interface(if_name(if_p)); 1808 } 1809 } 1810 all_services_ready(); 1811 } 1812 else if (ipconfig_method_is_v4(method)) { 1813 dynarray_add(&ifstate->services, service_p); 1814 } 1815 else { 1816 dynarray_add(&ifstate->services_v6, service_p); 1817 } 1818 1819 if (ret_service_p) { 1820 *ret_service_p = service_p; 1821 } 1822 return (status); 1823} 1824 1825static void 1826IFState_update_media_status(IFStateRef ifstate) 1827{ 1828 const char * ifname = if_name(ifstate->if_p); 1829 link_status_t link; 1830 1831 link = if_link_status_update(ifstate->if_p); 1832 if (link.valid == FALSE) { 1833 my_log(LOG_DEBUG, "%s link is unknown", ifname); 1834 } 1835 else { 1836 my_log(LOG_DEBUG, "%s link is %s", ifname, link.active ? "up" : "down"); 1837 } 1838 if (if_is_wireless(ifstate->if_p)) { 1839 struct ether_addr bssid; 1840 CFStringRef ssid; 1841 1842 ssid = S_copy_ssid_bssid(ifstate->ifname, &bssid); 1843 if (G_IPConfiguration_verbose) { 1844 if (ssid != NULL) { 1845 my_log(LOG_DEBUG, "%s: SSID %@ BSSID %s", 1846 if_name(ifstate->if_p), ssid, ether_ntoa(&bssid)); 1847 } 1848 else { 1849 my_log(LOG_DEBUG, "%s: no SSID", 1850 if_name(ifstate->if_p)); 1851 } 1852 } 1853 /* remember the ssid */ 1854 IFState_set_ssid_bssid(ifstate, ssid, &bssid); 1855 my_CFRelease(&ssid); 1856 } 1857 return; 1858} 1859 1860STATIC void 1861IFState_active_during_sleep_init(IFStateRef ifstate) 1862{ 1863 CFDictionaryRef dict; 1864 CFStringRef key; 1865 1866 key = ActiveDuringSleepRequestedKeyCopy(ifstate->ifname); 1867 dict = SCDynamicStoreCopyValue(S_scd_session, key); 1868 CFRelease(key); 1869 if (dict != NULL) { 1870 ifstate->active_during_sleep.requested = TRUE; 1871 CFRelease(dict); 1872 } 1873 return; 1874} 1875 1876static IFStateRef 1877IFState_init(interface_t * if_p) 1878{ 1879 IFStateRef ifstate; 1880 1881 ifstate = malloc(sizeof(*ifstate)); 1882 if (ifstate == NULL) { 1883 my_log(LOG_ERR, "IFState_init: malloc ifstate failed"); 1884 return (NULL); 1885 } 1886 bzero(ifstate, sizeof(*ifstate)); 1887 ifstate->if_p = if_dup(if_p); 1888 ifstate->ifname = CFStringCreateWithCString(NULL, if_name(if_p), 1889 kCFStringEncodingASCII); 1890 IFState_update_media_status(ifstate); 1891 IFState_active_during_sleep_init(ifstate); 1892 ifstate->timer = timer_callout_init(); 1893 dynarray_init(&ifstate->services, ServiceFree, NULL); 1894 dynarray_init(&ifstate->services_v6, ServiceFree, NULL); 1895 return (ifstate); 1896} 1897 1898static boolean_t 1899IFState_wireless_did_roam(IFStateRef ifstate, CFStringRef ssid, 1900 const struct ether_addr * bssid) 1901{ 1902 if (ssid != NULL 1903 && my_CFEqual(ssid, ifstate->ssid) 1904 && bcmp(bssid, &ifstate->bssid, sizeof(ifstate->bssid)) != 0) { 1905 return (TRUE); 1906 } 1907 return (FALSE); 1908} 1909 1910static void 1911IFState_set_bssid(IFStateRef ifstate, const struct ether_addr * bssid) 1912{ 1913 if (bssid != NULL) { 1914 ifstate->bssid = *bssid; 1915 } 1916 else { 1917 bzero(&ifstate->bssid, sizeof(ifstate->bssid)); 1918 } 1919 return; 1920} 1921 1922static void 1923IFState_set_ssid_bssid(IFStateRef ifstate, CFStringRef ssid, 1924 const struct ether_addr * bssid) 1925{ 1926 if (ssid != NULL) { 1927 CFRetain(ssid); 1928 } 1929 if (ifstate->ssid != NULL) { 1930 CFRelease(ifstate->ssid); 1931 } 1932 ifstate->ssid = ssid; 1933 IFState_set_bssid(ifstate, bssid); 1934 return; 1935} 1936 1937static void 1938IFState_free(void * arg) 1939{ 1940 IFStateRef ifstate = (IFStateRef)arg; 1941 1942 if (G_IPConfiguration_verbose) { 1943 my_log(LOG_DEBUG, "IFState_free(%s)", if_name(ifstate->if_p)); 1944 } 1945 IFStateFreeIPv4Services(ifstate, TRUE); 1946 IFStateFreeIPv6Services(ifstate, TRUE); 1947 my_CFRelease(&ifstate->ifname); 1948 my_CFRelease(&ifstate->neighbor_advert_list); 1949 IFState_set_ssid_bssid(ifstate, NULL, NULL); 1950 if_free(&ifstate->if_p); 1951 timer_callout_free(&ifstate->timer); 1952 free(ifstate); 1953 return; 1954} 1955 1956STATIC void 1957IFStateSetActiveDuringSleepNeedsAttention(IFStateRef ifstate) 1958{ 1959 S_active_during_sleep_needs_attention = TRUE; 1960 ifstate->active_during_sleep.needs_attention = TRUE; 1961 return; 1962} 1963 1964STATIC void 1965IFStateSetActiveDuringSleepRequested(IFStateRef ifstate, 1966 boolean_t ads_requested) 1967{ 1968 if (ads_requested != ifstate->active_during_sleep.requested) { 1969 /* active during sleep request changed */ 1970 my_log(LOG_DEBUG, "%s: active during sleep %srequested", 1971 if_name(ifstate->if_p), ads_requested ? "" : "not "); 1972 ifstate->active_during_sleep.requested = ads_requested; 1973 IFStateSetActiveDuringSleepNeedsAttention(ifstate); 1974 } 1975 return; 1976} 1977 1978STATIC void 1979IFStateProcessActiveDuringSleep(IFStateRef ifstate) 1980{ 1981 active_during_sleep_t active_during_sleep; 1982 CFDictionaryRef dict; 1983 1984 if (ifstate->active_during_sleep.needs_attention == FALSE) { 1985 return; 1986 } 1987 ifstate->active_during_sleep.needs_attention = FALSE; 1988 bzero(&active_during_sleep, sizeof(active_during_sleep)); 1989 active_during_sleep.requested 1990 = ifstate->active_during_sleep.requested; 1991 active_during_sleep.supported = TRUE; 1992 1993 /* v4 services */ 1994 service_list_event(&ifstate->services, IFEventID_active_during_sleep_e, 1995 &active_during_sleep); 1996#if 0 1997 /* v6 services */ 1998 service_list_event(&ifstate->services_v6, IFEventID_active_during_sleep_e, 1999 &active_during_sleep); 2000#endif 2001 if (ifstate->active_during_sleep.requested 2002 && active_during_sleep.supported) { 2003 /* indicate that sleep is supported */ 2004 dict = CFDictionaryCreate(NULL, 2005 NULL, NULL, 0, 2006 &kCFTypeDictionaryKeyCallBacks, 2007 &kCFTypeDictionaryValueCallBacks); 2008 } 2009 else { 2010 /* indicate that sleep is not supported */ 2011 dict = NULL; 2012 } 2013 my_SCDynamicStoreSetInterface(S_scd_session, 2014 ifstate->ifname, 2015 kSCEntNetInterfaceActiveDuringSleepSupported, 2016 dict); 2017 my_CFRelease(&dict); 2018 return; 2019} 2020 2021static IFStateRef 2022IFStateList_ifstate_with_name(IFStateList_t * list, const char * ifname, 2023 int * where) 2024{ 2025 int i; 2026 2027 for (i = 0; i < dynarray_count(list); i++) { 2028 IFStateRef element = dynarray_element(list, i); 2029 if (strcmp(if_name(element->if_p), ifname) == 0) { 2030 if (where != NULL) { 2031 *where = i; 2032 } 2033 return (element); 2034 } 2035 } 2036 return (NULL); 2037} 2038 2039static IFStateRef 2040IFStateListGetIFState(IFStateList_t * list, CFStringRef ifname, 2041 int * where) 2042{ 2043 int i; 2044 2045 for (i = 0; i < dynarray_count(list); i++) { 2046 IFStateRef element = dynarray_element(list, i); 2047 2048 if (CFEqual(ifname, element->ifname)) { 2049 if (where != NULL) { 2050 *where = i; 2051 } 2052 return (element); 2053 } 2054 } 2055 return (NULL); 2056} 2057 2058static IFStateRef 2059IFStateList_ifstate_create(IFStateList_t * list, interface_t * if_p) 2060{ 2061 IFStateRef ifstate; 2062 2063 ifstate = IFStateList_ifstate_with_name(list, if_name(if_p), NULL); 2064 if (ifstate == NULL) { 2065 ifstate = IFState_init(if_p); 2066 if (ifstate) { 2067 dynarray_add(list, ifstate); 2068 } 2069 } 2070 return (ifstate); 2071} 2072 2073static void 2074IFStateList_ifstate_free(IFStateList_t * list, const char * ifname) 2075{ 2076 IFStateRef ifstate; 2077 int where = -1; 2078 2079 ifstate = IFStateList_ifstate_with_name(list, ifname, &where); 2080 if (ifstate == NULL) { 2081 return; 2082 } 2083 dynarray_free_element(list, where); 2084 return; 2085} 2086 2087#ifdef DEBUG 2088static void 2089IFStateList_print(IFStateList_t * list) 2090{ 2091 int i; 2092 2093 printf("-------start--------\n"); 2094 for (i = 0; i < dynarray_count(list); i++) { 2095 IFStateRef ifstate = dynarray_element(list, i); 2096 int j; 2097 2098 printf("%s:", if_name(ifstate->if_p)); 2099 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 2100 ServiceRef service_p = dynarray_element(&ifstate->services, j); 2101 2102 printf("%s%s", (j == 0) ? "" : ", ", 2103 ipconfig_method_string(service_p->method)); 2104 } 2105 printf("\n"); 2106 } 2107 printf("-------end--------\n"); 2108 return; 2109} 2110#endif /* DEBUG */ 2111 2112static IFStateRef 2113IFStateListGetServiceWithID(IFStateList_t * list, CFStringRef serviceID, 2114 ServiceRef * ret_service, boolean_t is_ipv4) 2115{ 2116 int i; 2117 2118 for (i = 0; i < dynarray_count(list); i++) { 2119 IFStateRef ifstate = dynarray_element(list, i); 2120 ServiceRef service_p; 2121 2122 service_p = IFStateGetServiceWithID(ifstate, serviceID, is_ipv4); 2123 if (service_p) { 2124 if (ret_service) { 2125 *ret_service = service_p; 2126 } 2127 return (ifstate); 2128 } 2129 } 2130 if (ret_service) { 2131 *ret_service = NULL; 2132 } 2133 return (NULL); 2134} 2135 2136PRIVATE_EXTERN boolean_t 2137service_is_using_ip(ServiceRef exclude_service_p, struct in_addr iaddr) 2138{ 2139 int i; 2140 2141 for (i = 0; i < dynarray_count(&S_ifstate_list); i++) { 2142 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 2143 int j; 2144 2145 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 2146 ServiceRef service_p = dynarray_element(&ifstate->services, j); 2147 2148 if (service_p == exclude_service_p) { 2149 continue; 2150 } 2151 2152 if (service_p->u.v4.info.addr.s_addr == iaddr.s_addr) { 2153 return (TRUE); 2154 } 2155 } 2156 } 2157 return (FALSE); 2158 2159} 2160 2161/** 2162 ** netboot-specific routines 2163 **/ 2164PRIVATE_EXTERN void 2165netboot_addresses(struct in_addr * ip, struct in_addr * server_ip) 2166{ 2167 if (ip) 2168 *ip = S_netboot_ip; 2169 if (server_ip) 2170 *server_ip = S_netboot_server_ip; 2171} 2172 2173 2174#ifndef KERN_NETBOOT 2175#define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */ 2176#endif /* KERN_NETBOOT */ 2177 2178static boolean_t 2179S_netboot_root() 2180{ 2181 int mib[2]; 2182 size_t len; 2183 int netboot = 0; 2184 2185 mib[0] = CTL_KERN; 2186 mib[1] = KERN_NETBOOT; 2187 len = sizeof(netboot); 2188 sysctl(mib, 2, &netboot, &len, NULL, 0); 2189 return (netboot); 2190} 2191 2192static boolean_t 2193S_netboot_init() 2194{ 2195 CFDictionaryRef chosen = NULL; 2196 struct dhcp * dhcp; 2197 struct in_addr * iaddr_p; 2198 interface_t * if_p; 2199 IFStateRef ifstate; 2200 boolean_t is_dhcp = TRUE; 2201 int length; 2202 CFDataRef response = NULL; 2203 2204 if (S_netboot_root() == FALSE) { 2205 goto done; 2206 } 2207 2208 chosen = myIORegistryEntryCopyValue("IODeviceTree:/chosen"); 2209 if (chosen == NULL) { 2210 goto done; 2211 } 2212 response = CFDictionaryGetValue(chosen, CFSTR("dhcp-response")); 2213 if (isA_CFData(response) == NULL) { 2214 response = CFDictionaryGetValue(chosen, CFSTR("bootp-response")); 2215 if (isA_CFData(response) == NULL) { 2216 goto done; 2217 } 2218 is_dhcp = FALSE; 2219 } 2220 /* ALIGN: CFDataGetBytePtr should be at least sizeof(uint64_t) */ 2221 dhcp = (struct dhcp *)(void *)CFDataGetBytePtr(response); 2222 length = (int)CFDataGetLength(response); 2223 if (dhcp->dp_yiaddr.s_addr != 0) { 2224 S_netboot_ip = dhcp->dp_yiaddr; 2225 } 2226 else if (dhcp->dp_ciaddr.s_addr != 0) { 2227 S_netboot_ip = dhcp->dp_ciaddr; 2228 } 2229 else { 2230 goto done; 2231 } 2232 S_netboot_server_ip = dhcp->dp_siaddr; 2233 if_p = ifl_find_ip(S_interfaces, S_netboot_ip); 2234 if (if_p == NULL) { 2235 /* not netbooting: some interface (en0) must have the assigned IP */ 2236 goto done; 2237 } 2238 ifstate = IFStateList_ifstate_create(&S_ifstate_list, if_p); 2239 ifstate->netboot = TRUE; 2240 if (is_dhcp == TRUE) { 2241 dhcpol_t options; 2242 2243 (void)dhcpol_parse_packet(&options, dhcp, length, NULL); 2244 iaddr_p = (struct in_addr *) 2245 dhcpol_find_with_length(&options, 2246 dhcptag_server_identifier_e, 2247 sizeof(*iaddr_p)); 2248 if (iaddr_p != NULL) { 2249 S_netboot_server_ip = *iaddr_p; 2250 } 2251 dhcpol_free(&options); 2252 } 2253 strlcpy(S_netboot_ifname, if_name(if_p), sizeof(S_netboot_ifname)); 2254 G_is_netboot = TRUE; 2255 2256 done: 2257 my_CFRelease(&chosen); 2258 return (G_is_netboot); 2259} 2260 2261static void 2262set_entity_value(CFStringRef * entities, 2263 CFDictionaryRef * values, int size, 2264 CFStringRef entity, CFDictionaryRef value, 2265 int * count_p) 2266{ 2267 int i; 2268 2269 i = *count_p; 2270 if (i >= size) { 2271 my_log(LOG_ERR, "IPConfiguration: set_entity_value %d >= %d", 2272 i, size); 2273 return; 2274 } 2275 entities[i] = entity; 2276 values[i] = value; 2277 (*count_p)++; 2278 return; 2279} 2280 2281PRIVATE_EXTERN const char * 2282ServiceGetMethodString(ServiceRef service_p) 2283{ 2284 return (ipconfig_method_string(service_p->method)); 2285} 2286 2287static void 2288service_clear(ServiceRef service_p) 2289{ 2290 service_p->ready = FALSE; 2291 service_p->status = ipconfig_status_success_e; 2292 return; 2293} 2294 2295#define N_PUBLISH_ENTITIES 5 2296 2297static void 2298service_publish_clear(ServiceRef service_p) 2299{ 2300 CFDictionaryRef dns_dict = NULL; 2301 CFStringRef entities[N_PUBLISH_ENTITIES]; 2302 int entity_count; 2303 CFDictionaryRef values[N_PUBLISH_ENTITIES]; 2304 2305 service_clear(service_p); 2306 if (S_scd_session == NULL) { 2307 return; 2308 } 2309 if (ServiceIsIPv4(service_p)) { 2310 /* IPv4 */ 2311 entity_count = 0; 2312 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2313 kSCEntNetIPv4, NULL, &entity_count); 2314 dns_dict = ServiceIPv4CopyMergedDNS(service_p, NULL); 2315 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2316 kSCEntNetDNS, dns_dict, &entity_count); 2317 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2318 kSCEntNetDHCP, NULL, &entity_count); 2319#if ! TARGET_OS_EMBEDDED 2320 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2321 kSCEntNetSMB, NULL, &entity_count); 2322#endif /* ! TARGET_OS_EMBEDDED */ 2323 ServiceSetActiveDuringSleepNeedsAttention(service_p); 2324 } 2325 else { 2326 /* IPv6 */ 2327 entity_count = 0; 2328 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2329 kSCEntNetIPv6, NULL, &entity_count); 2330 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2331 kSCEntNetDHCPv6, NULL, &entity_count); 2332 dns_dict = ServiceIPv6CopyMergedDNS(service_p, NULL); 2333 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2334 kSCEntNetDNS, dns_dict, &entity_count); 2335 } 2336 my_SCDynamicStoreSetService(S_scd_session, 2337 service_p->serviceID, 2338 entities, values, entity_count, 2339 service_p->no_publish); 2340 my_CFRelease(&dns_dict); 2341 return; 2342} 2343 2344static boolean_t 2345all_services_ready() 2346{ 2347 int i; 2348 2349 for (i = 0; i < dynarray_count(&S_ifstate_list); i++) { 2350 int j; 2351 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 2352 2353 if (dynarray_count(&ifstate->services) == 0 2354 && ifstate->startup_ready == FALSE) { 2355 return (FALSE); 2356 } 2357 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 2358 ServiceRef service_p = dynarray_element(&ifstate->services, j); 2359 2360 if (service_p->ready == FALSE) { 2361 return (FALSE); 2362 } 2363 } 2364 } 2365 unblock_startup(S_scd_session); 2366 return (TRUE); 2367} 2368 2369static void 2370dict_insert_router_info(ServiceRef service_p, CFMutableDictionaryRef dict) 2371{ 2372 interface_t * if_p = service_interface(service_p); 2373 char link_addr[MAX_LINK_ADDR_LEN * 3]; 2374 CFStringRef link_addr_cf; 2375 CFStringRef router_ip; 2376 CFStringRef sig_str; 2377 2378 if (service_router_all_valid(service_p) == FALSE) { 2379 return; 2380 } 2381 2382 /* router IP address */ 2383 router_ip 2384 = CFStringCreateWithFormat(NULL, NULL, 2385 CFSTR(IP_FORMAT), 2386 IP_LIST(&service_p->u.v4.router.iaddr)); 2387 /* router link address */ 2388 link_addr_to_string(link_addr, sizeof(link_addr), 2389 service_p->u.v4.router.hwaddr, 2390 if_link_length(if_p)); 2391 link_addr_cf = CFStringCreateWithCString(NULL, 2392 link_addr, 2393 kCFStringEncodingASCII); 2394 2395 /* signature */ 2396 sig_str 2397 = CFStringCreateWithFormat(NULL, NULL, 2398 CFSTR("IPv4.Router=%@;IPv4.RouterHardwareAddress=%s"), 2399 router_ip, 2400 link_addr); 2401 CFDictionarySetValue(dict, kNetworkSignature, sig_str); 2402 CFDictionarySetValue(dict, kARPResolvedIPAddress, router_ip); 2403 CFDictionarySetValue(dict, kARPResolvedHardwareAddress, link_addr_cf); 2404 CFRelease(sig_str); 2405 CFRelease(router_ip); 2406 CFRelease(link_addr_cf); 2407 return; 2408} 2409 2410STATIC CFDictionaryRef 2411ServiceIPv4CopyMergedDNS(ServiceRef service_p, dhcp_info_t * info_p) 2412{ 2413 dhcpv6_info_t info_v6; 2414 ServiceRef ipv6_service_p; 2415 2416 ipv6_service_p = IFStateGetServiceWithID(service_p->ifstate, 2417 service_p->serviceID, 2418 IS_IPV6); 2419 bzero(&info_v6, sizeof(info_v6)); 2420 if (ipv6_service_p != NULL) { 2421 (void)config_method_event(ipv6_service_p, IFEventID_get_dhcpv6_info_e, 2422 &info_v6); 2423 } 2424 return (DNSEntityCreateWithDHCPv4AndDHCPv6Info(info_p, &info_v6)); 2425} 2426 2427#ifndef kSCPropConfirmedInterfaceName 2428#define kSCPropConfirmedInterfaceName CFSTR("ConfirmedInterfaceName") 2429#endif /* kSCPropConfirmedInterfaceName */ 2430 2431STATIC CFDictionaryRef 2432route_dict_create(const struct in_addr * dest, const struct in_addr * mask, 2433 const struct in_addr * gate) 2434{ 2435 int count = 0; 2436 CFDictionaryRef dict; 2437 int i; 2438#define N_KEYS 3 2439 const void * keys[N_KEYS]; 2440 CFStringRef values[N_KEYS]; 2441 2442 if (dest != NULL) { 2443 keys[count] = kSCPropNetIPv4RouteDestinationAddress; 2444 values[count] = my_CFStringCreateWithIPAddress(*dest); 2445 count++; 2446 } 2447 if (mask != NULL) { 2448 keys[count] = kSCPropNetIPv4RouteSubnetMask; 2449 values[count] = my_CFStringCreateWithIPAddress(*mask); 2450 count++; 2451 } 2452 if (gate != NULL) { 2453 keys[count] = kSCPropNetIPv4RouteGatewayAddress; 2454 values[count] = my_CFStringCreateWithIPAddress(*gate); 2455 count++; 2456 } 2457 if (count == 0) { 2458 return (NULL); 2459 } 2460 dict = CFDictionaryCreate(NULL, keys, (const void * *)values, 2461 count, 2462 &kCFTypeDictionaryKeyCallBacks, 2463 &kCFTypeDictionaryValueCallBacks); 2464 for (i = 0; i < count; i++) { 2465 CFRelease(values[i]); 2466 } 2467 return (dict); 2468} 2469 2470STATIC void 2471dict_insert_additional_routes(CFMutableDictionaryRef dict, 2472 struct in_addr addr) 2473{ 2474 struct in_addr linklocal_mask = { htonl(IN_CLASSB_NET) }; 2475 struct in_addr linklocal_network = { htonl(IN_LINKLOCALNETNUM) }; 2476 CFDictionaryRef route_dict[2]; 2477 CFArrayRef routes; 2478 2479 route_dict[0] = route_dict_create(&addr, &G_ip_broadcast, NULL); 2480 route_dict[1] = route_dict_create(&linklocal_network, &linklocal_mask, 2481 NULL); 2482 routes = CFArrayCreate(NULL, (const void * *)route_dict, 2483 sizeof(route_dict) / sizeof(route_dict[0]), 2484 &kCFTypeArrayCallBacks); 2485 CFRelease(route_dict[0]); 2486 CFRelease(route_dict[1]); 2487 CFDictionarySetValue(dict, kSCPropNetIPv4AdditionalRoutes, routes); 2488 CFRelease(routes); 2489 return; 2490} 2491 2492PRIVATE_EXTERN void 2493ServicePublishSuccessIPv4(ServiceRef service_p, dhcp_info_t * dhcp_info_p) 2494{ 2495 CFDictionaryRef dhcp_dict = NULL; 2496 CFDictionaryRef dns_dict = NULL; 2497 CFStringRef entities[N_PUBLISH_ENTITIES]; 2498 int entity_count; 2499 interface_t * if_p = service_interface(service_p); 2500 inet_addrinfo_t * info_p; 2501 CFMutableDictionaryRef ipv4_dict = NULL; 2502 dhcpol_t * options = NULL; 2503 ServiceRef parent_service_p = NULL; 2504 CFStringRef serviceID; 2505#if ! TARGET_OS_EMBEDDED 2506 CFMutableDictionaryRef smb_dict = NULL; 2507 const uint8_t * smb_nodetype = NULL; 2508 int smb_nodetype_len = 0; 2509 struct in_addr * smb_server = NULL; 2510 int smb_server_len = 0; 2511#endif /* ! TARGET_OS_EMBEDDED */ 2512 CFDictionaryRef values[N_PUBLISH_ENTITIES]; 2513 2514 if (service_p->serviceID == NULL) { 2515 return; 2516 } 2517 info_p = &service_p->u.v4.info; 2518 service_p->ready = TRUE; 2519 service_p->status = ipconfig_status_success_e; 2520 2521 if (S_scd_session == NULL) { 2522 /* configd is not running */ 2523 return; 2524 } 2525 if (dhcp_info_p != NULL) { 2526 options = dhcp_info_p->options; 2527 } 2528 if (service_p->parent_serviceID != NULL) { 2529 parent_service_p 2530 = IFStateGetServiceWithID(service_ifstate(service_p), 2531 service_p->parent_serviceID, 2532 IS_IPV4); 2533 if (parent_service_p == NULL 2534 || parent_service_p->u.v4.info.addr.s_addr != 0) { 2535 return; 2536 } 2537 serviceID = service_p->parent_serviceID; 2538 } 2539 else { 2540 serviceID = service_p->serviceID; 2541 } 2542 2543 /* IPv4 */ 2544 ipv4_dict = CFDictionaryCreateMutable(NULL, 0, 2545 &kCFTypeDictionaryKeyCallBacks, 2546 &kCFTypeDictionaryValueCallBacks); 2547 /* Addresses */ 2548 my_CFDictionarySetIPAddressAsArrayValue(ipv4_dict, 2549 kSCPropNetIPv4Addresses, 2550 info_p->addr); 2551 /* SubnetMasks */ 2552 my_CFDictionarySetIPAddressAsArrayValue(ipv4_dict, 2553 kSCPropNetIPv4SubnetMasks, 2554 info_p->mask); 2555 2556 /* InterfaceName */ 2557 CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, 2558 service_ifstate(service_p)->ifname); 2559 2560 if (service_ifstate(service_p)->netboot 2561 && service_p->parent_serviceID == NULL) { 2562 CFNumberRef primary; 2563 int enabled = 1; 2564 2565 /* ensure that we're the primary service */ 2566 primary = CFNumberCreate(NULL, kCFNumberIntType, &enabled); 2567 CFDictionarySetValue(ipv4_dict, kSCPropNetOverridePrimary, 2568 primary); 2569 CFRelease(primary); 2570 } 2571 2572 if (options != NULL) { 2573 char * host_name = NULL; 2574 int host_name_len = 0; 2575 2576 if (service_p->method == ipconfig_method_bootp_e 2577 || dhcp_parameter_is_ok(dhcptag_host_name_e)) { 2578 host_name = (char *) 2579 dhcpol_find(options, 2580 dhcptag_host_name_e, 2581 &host_name_len, NULL); 2582 /* set the hostname */ 2583 if (host_name && host_name_len > 0) { 2584 CFStringRef str; 2585 str = CFStringCreateWithBytes(NULL, (UInt8 *)host_name, 2586 host_name_len, 2587 kCFStringEncodingUTF8, 2588 FALSE); 2589 if (str != NULL) { 2590 CFDictionarySetValue(ipv4_dict, CFSTR("Hostname"), str); 2591 CFRelease(str); 2592 } 2593 } 2594 } 2595 if (dhcp_parameter_is_ok(dhcptag_router_e)) { 2596 struct in_addr * router = NULL; 2597 2598 router = (struct in_addr *) 2599 dhcpol_find_with_length(options, 2600 dhcptag_router_e, 2601 sizeof(*router)); 2602 /* set the router */ 2603 if (router != NULL) { 2604 CFStringRef str; 2605 2606 str = my_CFStringCreateWithIPAddress(*router); 2607 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str); 2608 CFRelease(str); 2609 } 2610 } 2611 } 2612 2613 if ((if_flags(if_p) & IFF_LOOPBACK) == 0) { 2614 /* insert the signature */ 2615 dict_insert_router_info(service_p, ipv4_dict); 2616 2617 /* AdditionalRoutes */ 2618 dict_insert_additional_routes(ipv4_dict, info_p->addr); 2619 2620 /* ConfirmedInterfaceName */ 2621 CFDictionarySetValue(ipv4_dict, kSCPropConfirmedInterfaceName, 2622 service_ifstate(service_p)->ifname); 2623 } 2624 2625 /* 2626 * Entity values can be NULL or not NULL. The values are accumulated in 2627 * the "values" array. 2628 */ 2629 entity_count = 0; 2630 2631 /* IPv4 */ 2632 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2633 kSCEntNetIPv4, ipv4_dict, &entity_count); 2634 2635 /* DNS */ 2636 if (parent_service_p != NULL) { 2637 dns_dict = ServiceIPv4CopyMergedDNS(parent_service_p, dhcp_info_p); 2638 } 2639 else { 2640 dns_dict = ServiceIPv4CopyMergedDNS(service_p, dhcp_info_p); 2641 } 2642 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2643 kSCEntNetDNS, dns_dict, &entity_count); 2644 2645#if ! TARGET_OS_EMBEDDED 2646 /* SMB */ 2647 if (options != NULL) { 2648 if (dhcp_parameter_is_ok(dhcptag_nb_over_tcpip_name_server_e)) { 2649 smb_server = (struct in_addr *) 2650 dhcpol_find(options, 2651 dhcptag_nb_over_tcpip_name_server_e, 2652 &smb_server_len, NULL); 2653 } 2654 if (dhcp_parameter_is_ok(dhcptag_nb_over_tcpip_node_type_e)) { 2655 smb_nodetype = (uint8_t *) 2656 dhcpol_find(options, 2657 dhcptag_nb_over_tcpip_node_type_e, 2658 &smb_nodetype_len, NULL); 2659 } 2660 } 2661 if ((smb_server && smb_server_len >= sizeof(struct in_addr)) 2662 || (smb_nodetype && smb_nodetype_len == sizeof(uint8_t))) { 2663 smb_dict 2664 = CFDictionaryCreateMutable(NULL, 0, 2665 &kCFTypeDictionaryKeyCallBacks, 2666 &kCFTypeDictionaryValueCallBacks); 2667 if (smb_server && smb_server_len >= sizeof(struct in_addr)) { 2668 CFMutableArrayRef array = NULL; 2669 int i; 2670 2671 array = CFArrayCreateMutable(NULL, 2672 smb_server_len / sizeof(struct in_addr), 2673 &kCFTypeArrayCallBacks); 2674 for (i = 0; i < (smb_server_len / sizeof(struct in_addr)); i++) { 2675 CFStringRef str; 2676 str = my_CFStringCreateWithIPAddress(smb_server[i]); 2677 CFArrayAppendValue(array, str); 2678 CFRelease(str); 2679 } 2680 CFDictionarySetValue(smb_dict, kSCPropNetSMBWINSAddresses, array); 2681 CFRelease(array); 2682 } 2683 if (smb_nodetype && smb_nodetype_len == sizeof(uint8_t)) { 2684 switch (smb_nodetype[0]) { 2685 case 1 : 2686 CFDictionarySetValue(smb_dict, kSCPropNetSMBNetBIOSNodeType, 2687 kSCValNetSMBNetBIOSNodeTypeBroadcast); 2688 break; 2689 case 2 : 2690 CFDictionarySetValue(smb_dict, kSCPropNetSMBNetBIOSNodeType, 2691 kSCValNetSMBNetBIOSNodeTypePeer); 2692 break; 2693 case 4: 2694 CFDictionarySetValue(smb_dict, kSCPropNetSMBNetBIOSNodeType, 2695 kSCValNetSMBNetBIOSNodeTypeMixed); 2696 break; 2697 case 8 : 2698 CFDictionarySetValue(smb_dict, kSCPropNetSMBNetBIOSNodeType, 2699 kSCValNetSMBNetBIOSNodeTypeHybrid); 2700 break; 2701 } 2702 } 2703 } 2704 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2705 kSCEntNetSMB, smb_dict, &entity_count); 2706#endif /* ! TARGET_OS_EMBEDDED */ 2707 2708 /* DHCP */ 2709 if (dhcp_info_p != NULL && dhcp_info_p->pkt_size != 0) { 2710 dhcp_dict = DHCPInfoDictionaryCreate(service_p->method, 2711 dhcp_info_p->options, 2712 dhcp_info_p->lease_start, 2713 dhcp_info_p->lease_expiration); 2714 } 2715 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2716 kSCEntNetDHCP, dhcp_dict, &entity_count); 2717 2718 my_SCDynamicStoreSetService(S_scd_session, 2719 serviceID, 2720 entities, values, entity_count, 2721 service_p->no_publish); 2722 my_CFRelease(&ipv4_dict); 2723 my_CFRelease(&dns_dict); 2724 my_CFRelease(&dhcp_dict); 2725#if ! TARGET_OS_EMBEDDED 2726 my_CFRelease(&smb_dict); 2727#endif /* ! TARGET_OS_EMBEDDED */ 2728 all_services_ready(); 2729 ServiceSetActiveDuringSleepNeedsAttention(service_p); 2730 return; 2731} 2732 2733PRIVATE_EXTERN boolean_t 2734ServiceDefendIPv4Address(ServiceRef service_p, arp_collision_data_t * arpc) 2735{ 2736 absolute_time_t current_time; 2737 boolean_t defended = FALSE; 2738 ServiceIPv4Ref v4_p = &service_p->u.v4; 2739 2740 current_time = timer_current_secs(); 2741 if (arpc->is_sleep_proxy 2742 || ((current_time - v4_p->ip_assigned_time) > 2743 S_defend_ip_address_interval_secs)) { 2744 if (v4_p->ip_conflict_count > 0 2745 && ((current_time - v4_p->ip_conflict_time) 2746 > S_defend_ip_address_interval_secs)) { 2747 /* 2748 * if it's been awhile since we last had to defend 2749 * our IP address, assume we defended it successfully 2750 * and start the conflict counter over again 2751 */ 2752 v4_p->ip_conflict_count = 0; 2753 } 2754 v4_p->ip_conflict_time = current_time; 2755 v4_p->ip_conflict_count++; 2756 if (v4_p->ip_conflict_count > S_defend_ip_address_count) { 2757 /* too many conflicts */ 2758 } 2759 else { 2760 arp_client_t * arp; 2761 interface_t * if_p = service_interface(service_p); 2762 2763 arp = arp_client_init(G_arp_session, if_p); 2764 if (arp == NULL) { 2765 my_log(LOG_ERR, 2766 "IPConfiguration: " 2767 "ServiceDefendIPv4Address arp_client_init failed"); 2768 } 2769 else { 2770 defended = arp_client_defend(arp, v4_p->info.addr); 2771 arp_client_free(&arp); 2772 my_log(LOG_NOTICE, "%s %s: defending IP " 2773 IP_FORMAT 2774 " against %s" 2775 EA_FORMAT 2776 " %d (of %d)", 2777 ServiceGetMethodString(service_p), if_name(if_p), 2778 IP_LIST(&v4_p->info.addr), 2779 arpc->is_sleep_proxy ? "BonjourSleepProxy " : "", 2780 EA_LIST(arpc->hwaddr), 2781 v4_p->ip_conflict_count, S_defend_ip_address_count); 2782 2783 } 2784 } 2785 } 2786 return (defended); 2787} 2788 2789static void 2790my_CFDictionarySetIPv6AddressAsString(CFMutableDictionaryRef dict, 2791 CFStringRef prop, 2792 struct in6_addr * ip6_addr) 2793{ 2794 CFStringRef str; 2795 2796 str = my_CFStringCreateWithIPv6Address(ip6_addr); 2797 CFDictionarySetValue(dict, prop, str); 2798 CFRelease(str); 2799 return; 2800} 2801 2802static void 2803dict_set_inet6_info(CFMutableDictionaryRef dict, 2804 inet6_addrinfo_t * addr, int addr_count) 2805{ 2806 CFMutableArrayRef address_list; 2807 int i; 2808 CFMutableArrayRef prefix_list; 2809 2810 address_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2811 prefix_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2812 for (i = 0; i < addr_count; i++) { 2813 CFStringRef str; 2814 CFNumberRef num; 2815 int val; 2816 2817 str = my_CFStringCreateWithIPv6Address(&(addr[i].addr)); 2818 CFArrayAppendValue(address_list, str); 2819 CFRelease(str); 2820 val = addr[i].prefix_length; 2821 num = CFNumberCreate(NULL, kCFNumberIntType, &val); 2822 CFArrayAppendValue(prefix_list, num); 2823 CFRelease(num); 2824 } 2825 CFDictionarySetValue(dict, kSCPropNetIPv6Addresses, address_list); 2826 CFRelease(address_list); 2827 CFDictionarySetValue(dict, kSCPropNetIPv6PrefixLength, prefix_list); 2828 CFRelease(prefix_list); 2829 return; 2830} 2831 2832STATIC CFDictionaryRef 2833ServiceIPv6CopyMergedDNS(ServiceRef service_p, dhcpv6_info_t * info_v6_p) 2834{ 2835 dhcp_info_t info; 2836 ServiceRef ipv4_service_p; 2837 2838 ipv4_service_p = IFStateGetServiceWithID(service_p->ifstate, 2839 service_p->serviceID, 2840 IS_IPV4); 2841 bzero(&info, sizeof(info)); 2842 if (ipv4_service_p != NULL) { 2843 (void)config_method_event(ipv4_service_p, IFEventID_get_dhcp_info_e, 2844 &info); 2845 } 2846 return (DNSEntityCreateWithDHCPv4AndDHCPv6Info(&info, info_v6_p)); 2847} 2848 2849PRIVATE_EXTERN void 2850ServicePublishSuccessIPv6(ServiceRef service_p, 2851 inet6_addrinfo_t * addresses, int addresses_count, 2852 struct in6_addr * router, int router_count, 2853 dhcpv6_info_t * dhcp_info_p, 2854 CFStringRef signature) 2855{ 2856 CFStringRef entities[N_PUBLISH_ENTITIES]; 2857 int entity_count; 2858 CFDictionaryRef dhcp_dict = NULL; 2859 CFDictionaryRef dns_dict = NULL; 2860 interface_t * if_p = service_interface(service_p); 2861 CFMutableDictionaryRef ipv6_dict = NULL; 2862 DHCPv6OptionListRef options = NULL; 2863 CFDictionaryRef values[N_PUBLISH_ENTITIES]; 2864 2865 if (service_p->serviceID == NULL) { 2866 return; 2867 } 2868 if (addresses == NULL || addresses_count == 0) { 2869 return; 2870 } 2871 service_p->ready = TRUE; 2872 service_p->status = ipconfig_status_success_e; 2873 2874 if (S_scd_session == NULL) { 2875 /* configd is not running */ 2876 return; 2877 } 2878 2879 if (dhcp_info_p != NULL) { 2880 options = dhcp_info_p->options; 2881 } 2882 2883 /* IPv6 */ 2884 ipv6_dict = CFDictionaryCreateMutable(NULL, 0, 2885 &kCFTypeDictionaryKeyCallBacks, 2886 &kCFTypeDictionaryValueCallBacks); 2887 2888 /* Addresses, PrefixLength */ 2889 dict_set_inet6_info(ipv6_dict, addresses, addresses_count); 2890 2891 /* Router */ 2892 if (router != NULL) { 2893 my_CFDictionarySetIPv6AddressAsString(ipv6_dict, 2894 kSCPropNetIPv6Router, 2895 router); 2896 } 2897 /* InterfaceName */ 2898 CFDictionarySetValue(ipv6_dict, kSCPropInterfaceName, 2899 service_ifstate(service_p)->ifname); 2900 2901 if ((if_flags(if_p) & IFF_LOOPBACK) == 0) { 2902 /* ConfirmedInterfaceName */ 2903 CFDictionarySetValue(ipv6_dict, kSCPropConfirmedInterfaceName, 2904 service_ifstate(service_p)->ifname); 2905 /* NetworkSignature */ 2906 if (signature != NULL) { 2907 CFDictionarySetValue(ipv6_dict, kNetworkSignature, 2908 signature); 2909 } 2910 } 2911 2912 /* DNS */ 2913 dns_dict = ServiceIPv6CopyMergedDNS(service_p, dhcp_info_p); 2914 2915 /* DHCPv6 */ 2916 if (options != NULL) { 2917 dhcp_dict = DHCPv6InfoDictionaryCreate(options); 2918 } 2919 2920 /* 2921 * Entity values can be NULL or not NULL. The values are accumulated in 2922 * the "values" array. 2923 */ 2924 entity_count = 0; 2925 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2926 kSCEntNetIPv6, ipv6_dict, &entity_count); 2927 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2928 kSCEntNetDNS, dns_dict, &entity_count); 2929 set_entity_value(entities, values, N_PUBLISH_ENTITIES, 2930 kSCEntNetDHCPv6, dhcp_dict, &entity_count); 2931 my_SCDynamicStoreSetService(S_scd_session, 2932 service_p->serviceID, 2933 entities, values, entity_count, 2934 service_p->no_publish); 2935 my_CFRelease(&ipv6_dict); 2936 my_CFRelease(&dns_dict); 2937 my_CFRelease(&dhcp_dict); 2938 return; 2939} 2940 2941PRIVATE_EXTERN void 2942service_publish_failure_sync(ServiceRef service_p, ipconfig_status_t status, 2943 boolean_t sync) 2944{ 2945 if (ipconfig_method_is_v4(service_p->method)) { 2946 ServiceRef child_service_p = NULL; 2947 ServiceRef parent_service_p = NULL; 2948 2949 if (service_p->child_serviceID != NULL) { 2950 child_service_p 2951 = IFStateGetServiceWithID(service_ifstate(service_p), 2952 service_p->child_serviceID, 2953 IS_IPV4); 2954 } 2955 if (service_p->parent_serviceID != NULL) { 2956 parent_service_p 2957 = IFStateGetServiceWithID(service_ifstate(service_p), 2958 service_p->parent_serviceID, 2959 IS_IPV4); 2960 } 2961 if (child_service_p != NULL 2962 && child_service_p->u.v4.info.addr.s_addr != 0) { 2963 ServicePublishSuccessIPv4(child_service_p, NULL); 2964 service_clear(service_p); 2965 } 2966 else if (parent_service_p != NULL 2967 && parent_service_p->u.v4.info.addr.s_addr == 0) { 2968 ipconfig_status_t status; 2969 2970 /* clear the information in the DynamicStore, but not the status */ 2971 status = parent_service_p->status; 2972 service_publish_clear(parent_service_p); 2973 parent_service_p->status = status; 2974 } 2975 else { 2976 service_publish_clear(service_p); 2977 } 2978 } 2979 else { 2980 service_publish_clear(service_p); 2981 } 2982 service_p->ready = TRUE; 2983 service_p->status = status; 2984 my_log(LOG_DEBUG, "%s %s: status = '%s'", 2985 ServiceGetMethodString(service_p), 2986 if_name(service_interface(service_p)), 2987 ipconfig_status_string(status)); 2988 if (sync == TRUE) { 2989 all_services_ready(); 2990 } 2991 return; 2992} 2993 2994PRIVATE_EXTERN void 2995service_publish_failure(ServiceRef service_p, ipconfig_status_t status) 2996{ 2997 service_publish_failure_sync(service_p, status, TRUE); 2998 return; 2999} 3000 3001PRIVATE_EXTERN int 3002service_enable_autoaddr(ServiceRef service_p) 3003{ 3004 return (inet_set_autoaddr(if_name(service_interface(service_p)), 1)); 3005} 3006 3007PRIVATE_EXTERN int 3008service_disable_autoaddr(ServiceRef service_p) 3009{ 3010 flush_routes(if_link_index(service_interface(service_p)), 3011 G_ip_zeroes, G_ip_zeroes); 3012 return (inet_set_autoaddr(if_name(service_interface(service_p)), 0)); 3013} 3014 3015#define RANK_LOWEST (1024 * 1024) 3016#define RANK_NONE (RANK_LOWEST + 1) 3017 3018static unsigned int 3019S_get_service_rank(CFArrayRef arr, ServiceRef service_p) 3020{ 3021 int i; 3022 CFStringRef serviceID = service_p->serviceID; 3023 3024 if (service_ifstate(service_p)->netboot 3025 && service_p->method == ipconfig_method_dhcp_e) { 3026 /* the netboot service is the best service */ 3027 return (0); 3028 } 3029 if (serviceID != NULL && arr != NULL) { 3030 CFIndex count = CFArrayGetCount(arr); 3031 3032 for (i = 0; i < count; i++) { 3033 CFStringRef s = isA_CFString(CFArrayGetValueAtIndex(arr, i)); 3034 3035 if (s == NULL) { 3036 continue; 3037 } 3038 if (CFEqual(serviceID, s)) { 3039 return (i); 3040 } 3041 } 3042 } 3043 return (RANK_LOWEST); 3044} 3045 3046static CFArrayRef 3047S_get_service_order(SCDynamicStoreRef session) 3048{ 3049 CFArrayRef order = NULL; 3050 CFStringRef ipv4_key = NULL; 3051 CFDictionaryRef ipv4_dict = NULL; 3052 3053 if (session == NULL) 3054 goto done; 3055 3056 ipv4_key 3057 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 3058 kSCDynamicStoreDomainSetup, 3059 kSCEntNetIPv4); 3060 if (ipv4_key == NULL) { 3061 goto done; 3062 } 3063 ipv4_dict = my_SCDynamicStoreCopyDictionary(session, ipv4_key); 3064 if (ipv4_dict != NULL) { 3065 order = CFDictionaryGetValue(ipv4_dict, kSCPropNetServiceOrder); 3066 order = isA_CFArray(order); 3067 if (order) { 3068 CFRetain(order); 3069 } 3070 } 3071 3072 done: 3073 my_CFRelease(&ipv4_key); 3074 my_CFRelease(&ipv4_dict); 3075 return (order); 3076} 3077 3078/* 3079 * Function: service_parent_service 3080 * Purpose: 3081 * Return the parent service pointer of the given service, if the 3082 * parent is valid. 3083 */ 3084PRIVATE_EXTERN ServiceRef 3085service_parent_service(ServiceRef service_p) 3086{ 3087 ipconfig_method_t method; 3088 3089 if (service_p == NULL || service_p->parent_serviceID == NULL) { 3090 return (NULL); 3091 } 3092 method = service_p->method; 3093 return (IFStateGetServiceWithID(service_ifstate(service_p), 3094 service_p->parent_serviceID, 3095 ipconfig_method_is_v4(method))); 3096} 3097 3098/* 3099 * Function: linklocal_service_change 3100 * 3101 * Purpose: 3102 * If we're the parent of the link-local service, 3103 * send a change message to the link-local service, asking it to 3104 * either allocate or not allocate an IP. 3105 */ 3106PRIVATE_EXTERN void 3107linklocal_service_change(ServiceRef parent_service_p, boolean_t allocate) 3108{ 3109 ipconfig_method_data_t method_data; 3110 IFStateRef ifstate = service_ifstate(parent_service_p); 3111 ServiceRef ll_service_p; 3112 ServiceRef ll_parent_p = NULL; 3113 boolean_t needs_stop; 3114 3115 /* if the interface has a user-configured service, ignore this request */ 3116 ll_service_p = ifstate->linklocal_service_p; 3117 if (ll_service_p != NULL) { 3118 if (ll_service_p->parent_serviceID == NULL) { 3119 /* don't touch user-configured link-local service */ 3120 return; 3121 } 3122 ll_parent_p = IFStateGetServiceWithID(ifstate, 3123 ll_service_p->parent_serviceID, 3124 IS_IPV4); 3125 } 3126 if (ll_parent_p == NULL) { 3127 linklocal_set_needs_attention(); 3128 return; 3129 } 3130 if (parent_service_p != ll_parent_p) { 3131 /* we're not the one that triggered the link-local service */ 3132 linklocal_set_needs_attention(); 3133 return; 3134 } 3135 bzero(&method_data, sizeof(method_data)); 3136 method_data.linklocal.allocate = allocate; 3137 (void)config_method_change(ll_service_p, 3138 ipconfig_method_linklocal_e, 3139 &method_data, &needs_stop); 3140 return; 3141} 3142 3143PRIVATE_EXTERN void 3144linklocal_set_needs_attention() 3145{ 3146 S_linklocal_needs_attention = TRUE; 3147 return; 3148} 3149 3150PRIVATE_EXTERN void 3151linklocal_set_address(ServiceRef ll_service_p, struct in_addr ll_addr) 3152{ 3153 IFStateRef ifstate = service_ifstate(ll_service_p); 3154 3155 ifstate->v4_link_local = ll_addr; 3156 return; 3157} 3158 3159PRIVATE_EXTERN struct in_addr 3160linklocal_get_address(ServiceRef ll_service_p) 3161{ 3162 IFStateRef ifstate = service_ifstate(ll_service_p); 3163 3164 return (ifstate->v4_link_local); 3165} 3166 3167/* 3168 * Function: S_linklocal_start 3169 * Purpose: 3170 * Start a child link-local service for the given parent service. 3171 */ 3172static void 3173S_linklocal_start(ServiceRef parent_service_p, boolean_t allocate) 3174 3175{ 3176 ipconfig_method_data_t method_data; 3177 IFStateRef ifstate = service_ifstate(parent_service_p); 3178 ServiceRef service_p; 3179 ipconfig_status_t status; 3180 3181 bzero(&method_data, sizeof(method_data)); 3182 method_data.linklocal.allocate = allocate; 3183 status = IFState_service_add(ifstate, NULL, ipconfig_method_linklocal_e, 3184 &method_data, parent_service_p, 3185 &service_p); 3186 if (status != ipconfig_status_success_e) { 3187 my_log(LOG_ERR, 3188 "IPConfiguration: failed to start link-local service on %s, %s", 3189 if_name(ifstate->if_p), 3190 ipconfig_status_string(status)); 3191 } 3192 return; 3193} 3194 3195/* 3196 * Function: S_linklocal_elect 3197 * Purpose: 3198 */ 3199static void 3200S_linklocal_elect(CFArrayRef service_order) 3201{ 3202 int i; 3203 3204 for (i = 0; i < dynarray_count(&S_ifstate_list); i++) { 3205 unsigned int best_rank = RANK_NONE; 3206 ServiceRef best_service_p = NULL; 3207 boolean_t election_required = TRUE; 3208 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 3209 int j; 3210 ServiceRef ll_parent_p = NULL; 3211 ServiceRef ll_service_p; 3212 unsigned int rank; 3213 3214 if (if_ift_type(ifstate->if_p) == IFT_LOOP) { 3215 /* skip loopback interface */ 3216 continue; 3217 } 3218 ll_service_p = ifstate->linklocal_service_p; 3219 if (ll_service_p != NULL) { 3220 if (ll_service_p->parent_serviceID == NULL) { 3221 election_required = FALSE; 3222 if (ll_service_p->u.v4.info.addr.s_addr != 0) { 3223 best_service_p = ll_service_p; 3224 best_rank = S_get_service_rank(service_order, ll_service_p); 3225 } 3226 } 3227 else { 3228 /* check whether linklocal parent service is still there */ 3229 ll_parent_p 3230 = IFStateGetServiceWithID(ifstate, 3231 ll_service_p->parent_serviceID, 3232 IS_IPV4); 3233 if (ll_parent_p == NULL) { 3234 /* parent of link-local service is gone, child goes too */ 3235 IFStateFreeService(ifstate, ll_service_p); 3236 ll_service_p = NULL; 3237 /* side-effect: ifstate->linklocal_service_p = NULL */ 3238 } 3239 } 3240 } 3241 if (election_required) { 3242 /* find the best parent service for the linklocal service */ 3243 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 3244 ServiceRef service_p; 3245 inet_addrinfo_t * info_p; 3246 3247 service_p = dynarray_element(&ifstate->services, j); 3248 if (service_p->method == ipconfig_method_linklocal_e) { 3249 /* skip existing child linklocal service */ 3250 continue; 3251 } 3252 info_p = &service_p->u.v4.info; 3253 if (info_p->addr.s_addr == 0) { 3254 if (service_p->method != ipconfig_method_dhcp_e 3255 || G_dhcp_failure_configures_linklocal == FALSE 3256 || (service_p->status != ipconfig_status_no_server_e)) { 3257 /* service isn't ready to be a parent */ 3258 continue; 3259 } 3260 } 3261 rank = S_get_service_rank(service_order, service_p); 3262 if (best_service_p == NULL 3263 || rank < best_rank 3264 || (best_service_p->u.v4.info.addr.s_addr == 0 3265 && info_p->addr.s_addr != 0)) { 3266 best_service_p = service_p; 3267 best_rank = rank; 3268 } 3269 } 3270 if (ll_parent_p != best_service_p) { 3271 /* best parent service changed */ 3272 if (ll_parent_p != NULL) { 3273 my_CFRelease(&ll_parent_p->child_serviceID); 3274 IFStateFreeService(ifstate, ll_service_p); 3275 } 3276 if (best_service_p != NULL) { 3277 boolean_t allocate = LINKLOCAL_NO_ALLOCATE; 3278 3279 if (best_service_p->u.v4.info.addr.s_addr == 0) { 3280 /* service has no IP address, allocate a linklocal IP */ 3281 allocate = LINKLOCAL_ALLOCATE; 3282 } 3283 S_linklocal_start(best_service_p, allocate); 3284 } 3285 } 3286 } 3287 } 3288 return; 3289} 3290 3291PRIVATE_EXTERN int 3292service_set_address(ServiceRef service_p, 3293 struct in_addr addr, 3294 struct in_addr mask, 3295 struct in_addr broadcast) 3296{ 3297 interface_t * if_p = service_interface(service_p); 3298 int ret = 0; 3299 struct in_addr netaddr = { 0 }; 3300 int s = inet_dgram_socket(); 3301 3302 if (mask.s_addr == 0) { 3303 u_int32_t ipval = ntohl(addr.s_addr); 3304 3305 if (IN_CLASSA(ipval)) { 3306 mask.s_addr = htonl(IN_CLASSA_NET); 3307 } 3308 else if (IN_CLASSB(ipval)) { 3309 mask.s_addr = htonl(IN_CLASSB_NET); 3310 } 3311 else { 3312 mask.s_addr = htonl(IN_CLASSC_NET); 3313 } 3314 } 3315 if (broadcast.s_addr == 0) { 3316 broadcast = hltoip(iptohl(addr) | ~iptohl(mask)); 3317 } 3318 netaddr = hltoip(iptohl(addr) & iptohl(mask)); 3319 3320 if (G_IPConfiguration_verbose) { 3321 my_log(LOG_DEBUG, 3322 "%s %s: setting " IP_FORMAT " netmask " IP_FORMAT 3323 " broadcast " IP_FORMAT, 3324 ServiceGetMethodString(service_p), 3325 if_name(if_p), 3326 IP_LIST(&addr), IP_LIST(&mask), IP_LIST(&broadcast)); 3327 } 3328 if (s < 0) { 3329 ret = errno; 3330 my_log(LOG_ERR, 3331 "service_set_address(%s): socket() failed, %s (%d)", 3332 if_name(if_p), strerror(errno), errno); 3333 } 3334 else { 3335 inet_addrinfo_t * info_p = &service_p->u.v4.info; 3336 3337 if (inet_aifaddr(s, if_name(if_p), addr, &mask, &broadcast) < 0) { 3338 ret = errno; 3339 my_log(LOG_DEBUG, "service_set_address(%s) " 3340 IP_FORMAT " inet_aifaddr() failed, %s (%d)", if_name(if_p), 3341 IP_LIST(&addr), strerror(errno), errno); 3342 } 3343 bzero(info_p, sizeof(*info_p)); 3344 info_p->addr = addr; 3345 info_p->mask = mask; 3346 info_p->netaddr = netaddr; 3347 info_p->broadcast = broadcast; 3348 close(s); 3349 } 3350 service_p->u.v4.ip_assigned_time = timer_current_secs(); 3351 service_p->u.v4.ip_conflict_count = 0; 3352 3353 flush_routes(if_link_index(if_p), G_ip_zeroes, broadcast); 3354 linklocal_set_needs_attention(); 3355 return (ret); 3356} 3357 3358static int 3359S_remove_ip_address(const char * ifname, struct in_addr this_ip) 3360{ 3361 int ret = 0; 3362 int s; 3363 3364 s = inet_dgram_socket(); 3365 if (s < 0) { 3366 ret = errno; 3367 my_log(LOG_DEBUG, 3368 "S_remove_ip_address(%s) socket() failed, %s (%d)", 3369 ifname, strerror(errno), errno); 3370 } 3371 else { 3372 if (inet_difaddr(s, ifname, this_ip) < 0) { 3373 ret = errno; 3374 my_log(LOG_DEBUG, "S_remove_ip_address(%s) " 3375 IP_FORMAT " failed, %s (%d)", ifname, 3376 IP_LIST(&this_ip), strerror(errno), errno); 3377 } 3378 close(s); 3379 } 3380 return (ret); 3381} 3382 3383int 3384service_remove_address(ServiceRef service_p) 3385{ 3386 interface_t * if_p = service_interface(service_p); 3387 inet_addrinfo_t * info_p = &service_p->u.v4.info; 3388 int ret = 0; 3389 3390 if (info_p->addr.s_addr != 0) { 3391 inet_addrinfo_t saved_info; 3392 3393 /* copy IP info then clear it so that it won't be elected */ 3394 saved_info = service_p->u.v4.info; 3395 bzero(info_p, sizeof(*info_p)); 3396 3397 /* if no service on this interface refers to this IP, remove the IP */ 3398 if (IFState_service_with_ip(service_ifstate(service_p), 3399 saved_info.addr) == NULL) { 3400 /* 3401 * This can only happen if there's a manual/inform service 3402 * and a BOOTP/DHCP service with the same IP. Duplicate 3403 * manual/inform services are prevented when created. 3404 */ 3405 if (G_IPConfiguration_verbose) { 3406 my_log(LOG_DEBUG, "%s %s: removing " IP_FORMAT, 3407 ServiceGetMethodString(service_p), 3408 if_name(if_p), IP_LIST(&saved_info.addr)); 3409 } 3410 ret = S_remove_ip_address(if_name(if_p), saved_info.addr); 3411 } 3412 flush_routes(if_link_index(if_p), 3413 saved_info.addr, saved_info.broadcast); 3414 } 3415 linklocal_set_needs_attention(); 3416 return (ret); 3417} 3418 3419/** 3420 ** ServiceRef accessor routines 3421 **/ 3422 3423PRIVATE_EXTERN interface_t * 3424service_interface(ServiceRef service_p) 3425{ 3426 return (service_p->ifstate->if_p); 3427} 3428 3429PRIVATE_EXTERN link_status_t 3430service_link_status(ServiceRef service_p) 3431{ 3432 return (if_get_link_status(service_interface(service_p))); 3433} 3434 3435 3436PRIVATE_EXTERN bool 3437service_is_address_set(ServiceRef service_p) 3438{ 3439 if (ServiceIsIPv4(service_p)) { 3440 ServiceIPv4Ref v4_p = &service_p->u.v4; 3441 3442 return (v4_p->info.addr.s_addr == v4_p->requested_ip.addr.s_addr); 3443 } 3444 return (FALSE); 3445} 3446 3447PRIVATE_EXTERN void 3448service_set_requested_ip_addr(ServiceRef service_p, struct in_addr ip) 3449{ 3450 if (ServiceIsIPv4(service_p)) { 3451 ServiceIPv4Ref v4_p = &service_p->u.v4; 3452 3453 v4_p->requested_ip.addr = ip; 3454 } 3455 return; 3456} 3457 3458PRIVATE_EXTERN struct in_addr 3459service_requested_ip_addr(ServiceRef service_p) 3460{ 3461 if (ServiceIsIPv4(service_p)) { 3462 ServiceIPv4Ref v4_p = &service_p->u.v4; 3463 3464 return (v4_p->requested_ip.addr); 3465 } 3466 return (G_ip_zeroes); 3467} 3468 3469PRIVATE_EXTERN void 3470service_set_requested_ip_mask(ServiceRef service_p, struct in_addr mask) 3471{ 3472 if (ServiceIsIPv4(service_p)) { 3473 ServiceIPv4Ref v4_p = &service_p->u.v4; 3474 3475 v4_p->requested_ip.mask = mask; 3476 } 3477 return; 3478} 3479 3480PRIVATE_EXTERN struct in_addr 3481service_requested_ip_mask(ServiceRef service_p) 3482{ 3483 if (ServiceIsIPv4(service_p)) { 3484 ServiceIPv4Ref v4_p = &service_p->u.v4; 3485 3486 return (v4_p->requested_ip.mask); 3487 } 3488 return (G_ip_zeroes); 3489} 3490 3491PRIVATE_EXTERN boolean_t 3492service_router_is_hwaddr_valid(ServiceRef service_p) 3493{ 3494 if (ServiceIsIPv4(service_p)) { 3495 ServiceIPv4Ref v4_p = &service_p->u.v4; 3496 3497 return ((v4_p->router.flags & RIFLAGS_HWADDR_VALID) != 0); 3498 } 3499 return (FALSE); 3500} 3501 3502PRIVATE_EXTERN void 3503service_router_set_hwaddr_valid(ServiceRef service_p) 3504{ 3505 if (ServiceIsIPv4(service_p)) { 3506 ServiceIPv4Ref v4_p = &service_p->u.v4; 3507 3508 v4_p->router.flags |= RIFLAGS_HWADDR_VALID; 3509 } 3510 return; 3511} 3512 3513PRIVATE_EXTERN void 3514service_router_clear_hwaddr_valid(ServiceRef service_p) 3515{ 3516 if (ServiceIsIPv4(service_p)) { 3517 ServiceIPv4Ref v4_p = &service_p->u.v4; 3518 3519 v4_p->router.flags &= ~RIFLAGS_HWADDR_VALID; 3520 } 3521 return; 3522} 3523 3524PRIVATE_EXTERN boolean_t 3525service_router_is_iaddr_valid(ServiceRef service_p) 3526{ 3527 if (ServiceIsIPv4(service_p)) { 3528 ServiceIPv4Ref v4_p = &service_p->u.v4; 3529 3530 return ((v4_p->router.flags & RIFLAGS_IADDR_VALID) != 0); 3531 } 3532 return (FALSE); 3533} 3534 3535PRIVATE_EXTERN void 3536service_router_set_iaddr_valid(ServiceRef service_p) 3537{ 3538 if (ServiceIsIPv4(service_p)) { 3539 ServiceIPv4Ref v4_p = &service_p->u.v4; 3540 3541 v4_p->router.flags |= RIFLAGS_IADDR_VALID; 3542 } 3543 return; 3544} 3545 3546PRIVATE_EXTERN void 3547service_router_clear_iaddr_valid(ServiceRef service_p) 3548{ 3549 if (ServiceIsIPv4(service_p)) { 3550 ServiceIPv4Ref v4_p = &service_p->u.v4; 3551 3552 v4_p->router.flags &= ~RIFLAGS_IADDR_VALID; 3553 } 3554 return; 3555} 3556 3557PRIVATE_EXTERN boolean_t 3558service_router_is_arp_verified(ServiceRef service_p) 3559{ 3560 if (ServiceIsIPv4(service_p)) { 3561 ServiceIPv4Ref v4_p = &service_p->u.v4; 3562 return ((v4_p->router.flags & RIFLAGS_ARP_VERIFIED) != 0); 3563 } 3564 return (FALSE); 3565} 3566 3567PRIVATE_EXTERN void 3568service_router_set_arp_verified(ServiceRef service_p) 3569{ 3570 if (ServiceIsIPv4(service_p)) { 3571 ServiceIPv4Ref v4_p = &service_p->u.v4; 3572 3573 v4_p->router.flags |= RIFLAGS_ARP_VERIFIED; 3574 } 3575 return; 3576} 3577 3578PRIVATE_EXTERN void 3579service_router_clear_arp_verified(ServiceRef service_p) 3580{ 3581 if (ServiceIsIPv4(service_p)) { 3582 ServiceIPv4Ref v4_p = &service_p->u.v4; 3583 3584 v4_p->router.flags &= ~RIFLAGS_ARP_VERIFIED; 3585 } 3586 return; 3587} 3588 3589PRIVATE_EXTERN void 3590service_router_clear(ServiceRef service_p) 3591{ 3592 if (ServiceIsIPv4(service_p)) { 3593 ServiceIPv4Ref v4_p = &service_p->u.v4; 3594 3595 v4_p->router.flags = 0; 3596 } 3597 return; 3598} 3599 3600PRIVATE_EXTERN uint8_t * 3601service_router_hwaddr(ServiceRef service_p) 3602{ 3603 if (ServiceIsIPv4(service_p)) { 3604 ServiceIPv4Ref v4_p = &service_p->u.v4; 3605 return (v4_p->router.hwaddr); 3606 } 3607 return (NULL); 3608} 3609 3610PRIVATE_EXTERN int 3611service_router_hwaddr_size(ServiceRef service_p) 3612{ 3613 if (ServiceIsIPv4(service_p)) { 3614 ServiceIPv4Ref v4_p = &service_p->u.v4; 3615 return (sizeof(v4_p->router.hwaddr)); 3616 } 3617 return (0); 3618} 3619 3620PRIVATE_EXTERN struct in_addr 3621service_router_iaddr(ServiceRef service_p) 3622{ 3623 if (ServiceIsIPv4(service_p)) { 3624 ServiceIPv4Ref v4_p = &service_p->u.v4; 3625 3626 return (v4_p->router.iaddr); 3627 } 3628 return (G_ip_zeroes); 3629} 3630 3631PRIVATE_EXTERN void 3632service_router_set_iaddr(ServiceRef service_p, struct in_addr iaddr) 3633{ 3634 if (ServiceIsIPv4(service_p)) { 3635 ServiceIPv4Ref v4_p = &service_p->u.v4; 3636 3637 v4_p->router.iaddr = iaddr; 3638 } 3639 return; 3640} 3641 3642PRIVATE_EXTERN boolean_t 3643service_router_all_valid(ServiceRef service_p) 3644{ 3645 if (ServiceIsIPv4(service_p)) { 3646 ServiceIPv4Ref v4_p = &service_p->u.v4; 3647 3648 return ((v4_p->router.flags & RIFLAGS_ALL_VALID) == RIFLAGS_ALL_VALID); 3649 } 3650 return (FALSE); 3651} 3652 3653PRIVATE_EXTERN void 3654service_router_set_all_valid(ServiceRef service_p) 3655{ 3656 if (ServiceIsIPv4(service_p)) { 3657 ServiceIPv4Ref v4_p = &service_p->u.v4; 3658 3659 v4_p->router.flags = RIFLAGS_ALL_VALID; 3660 } 3661 return; 3662} 3663 3664PRIVATE_EXTERN boolean_t 3665ServiceIsIPv4(ServiceRef service_p) 3666{ 3667 return (ipconfig_method_is_v4(service_p->method)); 3668} 3669 3670PRIVATE_EXTERN boolean_t 3671ServiceIsIPv6(ServiceRef service_p) 3672{ 3673 return (ipconfig_method_is_v6(service_p->method)); 3674} 3675 3676PRIVATE_EXTERN boolean_t 3677ServiceIsNetBoot(ServiceRef service_p) 3678{ 3679 return (service_p->ifstate->netboot); 3680} 3681 3682PRIVATE_EXTERN void * 3683ServiceGetPrivate(ServiceRef service_p) 3684{ 3685 return (service_p->private); 3686} 3687 3688PRIVATE_EXTERN void 3689ServiceSetPrivate(ServiceRef service_p, void * private) 3690{ 3691 service_p->private = private; 3692 return; 3693} 3694 3695PRIVATE_EXTERN struct in_addr 3696ServiceGetActiveIPAddress(ServiceRef service_p) 3697{ 3698 if (ServiceIsIPv4(service_p)) { 3699 return (service_p->u.v4.info.addr); 3700 } 3701 return (G_ip_zeroes); 3702} 3703 3704PRIVATE_EXTERN struct in_addr 3705ServiceGetActiveSubnetMask(ServiceRef service_p) 3706{ 3707 if (ServiceIsIPv4(service_p)) { 3708 return (service_p->u.v4.info.mask); 3709 } 3710 return (G_ip_zeroes); 3711} 3712 3713PRIVATE_EXTERN void 3714ServiceSetStatus(ServiceRef service_p, ipconfig_status_t status) 3715{ 3716 service_p->status = status; 3717 return; 3718} 3719 3720PRIVATE_EXTERN void 3721ServiceSetRequestedIPv6Address(ServiceRef service_p, 3722 const struct in6_addr * addr_p, 3723 int prefix_length) 3724{ 3725 if (ServiceIsIPv6(service_p) == FALSE) { 3726 return; 3727 } 3728 service_p->u.v6.requested_ip.addr = *addr_p; 3729 service_p->u.v6.requested_ip.prefix_length = prefix_length; 3730 return; 3731} 3732 3733PRIVATE_EXTERN void 3734ServiceGetRequestedIPv6Address(ServiceRef service_p, 3735 struct in6_addr * addr_p, 3736 int * prefix_length) 3737{ 3738 if (ServiceIsIPv6(service_p) == FALSE) { 3739 return; 3740 } 3741 *addr_p = service_p->u.v6.requested_ip.addr; 3742 *prefix_length = service_p->u.v6.requested_ip.prefix_length; 3743 return; 3744} 3745 3746PRIVATE_EXTERN int 3747ServiceSetIPv6Address(ServiceRef service_p, const struct in6_addr * addr_p, 3748 int prefix_length, 3749 u_int32_t flags, 3750 u_int32_t valid_lifetime, 3751 u_int32_t preferred_lifetime) 3752{ 3753 interface_t * if_p = service_interface(service_p); 3754 int ret = 0; 3755 int s; 3756 3757 if (ServiceIsIPv6(service_p) == FALSE) { 3758 return (EINVAL); 3759 } 3760 if (G_IPConfiguration_verbose) { 3761 char ntopbuf[INET6_ADDRSTRLEN]; 3762 3763 my_log(LOG_DEBUG, "%s %s: setting %s/%d", 3764 ServiceGetMethodString(service_p), 3765 if_name(if_p), 3766 inet_ntop(AF_INET6, addr_p, ntopbuf, sizeof(ntopbuf)), 3767 prefix_length); 3768 } 3769 s = inet6_dgram_socket(); 3770 if (s < 0) { 3771 ret = errno; 3772 my_log(LOG_ERR, 3773 "ServiceSetIPv6Address(%s): socket() failed, %s (%d)", 3774 if_name(if_p), strerror(errno), errno); 3775 } 3776 else { 3777 if (inet6_aifaddr(s, if_name(if_p), addr_p, NULL, prefix_length, flags, 3778 valid_lifetime, preferred_lifetime) < 0) { 3779 ret = errno; 3780 my_log(LOG_DEBUG, 3781 "ServiceSetIPv6Address(%s): socket() failed, %s (%d)", 3782 if_name(if_p), strerror(errno), errno); 3783 } 3784 close(s); 3785 } 3786 return (ret); 3787} 3788 3789PRIVATE_EXTERN void 3790ServiceRemoveIPv6Address(ServiceRef service_p, 3791 const struct in6_addr * addr_p, int prefix_length) 3792{ 3793 interface_t * if_p = service_interface(service_p); 3794 int s; 3795 3796 if (ServiceIsIPv6(service_p) == FALSE) { 3797 return; 3798 } 3799 if (IN6_IS_ADDR_UNSPECIFIED(addr_p)) { 3800 /* no address assigned */ 3801 return; 3802 } 3803 if (G_IPConfiguration_verbose) { 3804 char ntopbuf[INET6_ADDRSTRLEN]; 3805 3806 my_log(LOG_DEBUG, 3807 "%s %s: removing %s/%d", 3808 ServiceGetMethodString(service_p), 3809 if_name(if_p), 3810 inet_ntop(AF_INET6, addr_p, ntopbuf, sizeof(ntopbuf)), 3811 prefix_length); 3812 } 3813 s = inet6_dgram_socket(); 3814 if (s < 0) { 3815 my_log(LOG_ERR, 3816 "ServiceRemoveIPv6Address(%s): socket() failed, %s (%d)", 3817 if_name(if_p), strerror(errno), errno); 3818 } 3819 else { 3820 inet6_difaddr(s, if_name(if_p), addr_p); 3821 close(s); 3822 } 3823 return; 3824} 3825 3826PRIVATE_EXTERN CFStringRef 3827ServiceGetSSID(ServiceRef service_p) 3828{ 3829 return (service_p->ifstate->ssid); 3830} 3831 3832PRIVATE_EXTERN void 3833ServiceSetActiveDuringSleepNeedsAttention(ServiceRef service_p) 3834{ 3835 IFStateSetActiveDuringSleepNeedsAttention(service_ifstate(service_p)); 3836 return; 3837} 3838 3839/** 3840 ** other 3841 **/ 3842static void 3843set_loopback() 3844{ 3845 struct in_addr loopback; 3846 struct in_addr loopback_net; 3847 struct in_addr loopback_mask; 3848 int s = inet_dgram_socket(); 3849 3850#ifndef INADDR_LOOPBACK_NET 3851#define INADDR_LOOPBACK_NET (u_int32_t)0x7f000000 3852#endif /* INADDR_LOOPBACK_NET */ 3853 3854 loopback.s_addr = htonl(INADDR_LOOPBACK); 3855 loopback_mask.s_addr = htonl(IN_CLASSA_NET); 3856 loopback_net.s_addr = htonl(INADDR_LOOPBACK_NET); 3857 3858 if (s < 0) { 3859 my_log(LOG_ERR, 3860 "set_loopback(): socket() failed, %s (%d)", 3861 strerror(errno), errno); 3862 return; 3863 } 3864 if (inet_aifaddr(s, "lo0", loopback, &loopback_mask, NULL) < 0) { 3865 my_log(LOG_DEBUG, "set_loopback: inet_aifaddr() failed, %s (%d)", 3866 strerror(errno), errno); 3867 } 3868 close(s); 3869 3870 /* add 127/8 route */ 3871 if (subnet_route_add(loopback, loopback_net, loopback_mask, "lo0") 3872 == FALSE) { 3873 my_log(LOG_DEBUG, "set_loopback: subnet_route_add() failed, %s (%d)", 3874 strerror(errno), errno); 3875 } 3876 return; 3877} 3878 3879void 3880remove_unused_ip(const char * ifname, struct in_addr ip) 3881{ 3882 IFStateRef ifstate; 3883 3884 /* if no service on this interface refers to this IP, remove the IP */ 3885 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, ifname, NULL); 3886 if (ifstate != NULL 3887 && IFState_service_with_ip(ifstate, ip) == NULL) { 3888 if (G_IPConfiguration_verbose) { 3889 my_log(LOG_DEBUG, "IPConfiguration %s: removing " IP_FORMAT, 3890 ifname, IP_LIST(&ip)); 3891 } 3892 S_remove_ip_address(if_name(ifstate->if_p), ip); 3893 } 3894 return; 3895} 3896 3897 3898/** 3899 ** Routines for MiG interface 3900 **/ 3901 3902extern ipconfig_status_t 3903ipconfig_method_info_from_plist(CFPropertyListRef plist, 3904 ipconfig_method_t * method_p, 3905 ipconfig_method_data_t * * method_data_p) 3906{ 3907 CFDictionaryRef dict; 3908 boolean_t is_ipv4; 3909 ipconfig_status_t status = ipconfig_status_invalid_parameter_e; 3910 3911 *method_p = ipconfig_method_none_e; 3912 *method_data_p = NULL; 3913 3914 if (plist == NULL) { 3915 /* NULL means no config method i.e. ipconfig_method_none_e */ 3916 status = ipconfig_status_success_e; 3917 goto done; 3918 } 3919 if (isA_CFDictionary(plist) == NULL) { 3920 /* if specified, plist must be a dictionary */ 3921 goto done; 3922 } 3923 /* if dictionary contains IPv4 dict, use that */ 3924 dict = CFDictionaryGetValue((CFDictionaryRef)plist, kSCEntNetIPv4); 3925 if (dict != NULL) { 3926 is_ipv4 = TRUE; 3927 } 3928 else { 3929 dict = CFDictionaryGetValue((CFDictionaryRef)plist, kSCEntNetIPv6); 3930 if (dict != NULL) { 3931 is_ipv4 = FALSE; 3932 } 3933 else { 3934 dict = (CFDictionaryRef)plist; 3935 is_ipv4 = TRUE; 3936 } 3937 } 3938 if (isA_CFDictionary(dict) == NULL) { 3939 my_log(LOG_ERR, "IPConfiguration: invalid IPv%c entity", 3940 is_ipv4 ? '4' : '6'); 3941 goto done; 3942 } 3943 if (CFDictionaryGetCount(dict) == 0) { 3944 *method_p = (is_ipv4) 3945 ? ipconfig_method_none_v4_e 3946 : ipconfig_method_none_v6_e; 3947 status = ipconfig_status_success_e; 3948 goto done; 3949 } 3950 if (is_ipv4) { 3951 status = method_info_from_dict(dict, method_p, method_data_p); 3952 } 3953 else { 3954 status = method_info_from_ipv6_dict(dict, method_p, method_data_p); 3955 } 3956 3957 done: 3958 return (status); 3959} 3960 3961static boolean_t 3962service_get_option(ServiceRef service_p, int option_code, void * option_data, 3963 unsigned int * option_dataCnt) 3964{ 3965 boolean_t ret = FALSE; 3966 3967 switch (service_p->method) { 3968 case ipconfig_method_inform_e: 3969 case ipconfig_method_dhcp_e: 3970 case ipconfig_method_bootp_e: { 3971 void * data; 3972 dhcp_info_t dhcp_info; 3973 int len; 3974 3975 if (service_p->ready == FALSE) { 3976 break; 3977 } 3978 bzero(&dhcp_info, sizeof(dhcp_info)); 3979 (void)config_method_event(service_p, IFEventID_get_dhcp_info_e, 3980 &dhcp_info); 3981 if (dhcp_info.pkt_size == 0) { 3982 break; /* out of switch */ 3983 } 3984 data = dhcpol_find(dhcp_info.options, option_code, 3985 &len, NULL); 3986 if (data) { 3987 if (len > *option_dataCnt) { 3988 break; /* out of switch */ 3989 } 3990 *option_dataCnt = len; 3991 bcopy(data, option_data, *option_dataCnt); 3992 ret = TRUE; 3993 } 3994 break; 3995 } 3996 default: 3997 break; 3998 } /* switch */ 3999 return (ret); 4000} 4001 4002int 4003get_if_count() 4004{ 4005 return (dynarray_count(&S_ifstate_list)); 4006} 4007 4008ipconfig_status_t 4009get_if_addr(const char * name, u_int32_t * addr) 4010{ 4011 IFStateRef ifstate; 4012 int j; 4013 4014 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, name, NULL); 4015 if (ifstate == NULL) { 4016 return (ipconfig_status_interface_does_not_exist_e); 4017 } 4018 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 4019 ServiceRef service_p = dynarray_element(&ifstate->services, j); 4020 4021 if (service_p->u.v4.info.addr.s_addr != 0) { 4022 *addr = service_p->u.v4.info.addr.s_addr; 4023 return (ipconfig_status_success_e); 4024 } 4025 } 4026 return (ipconfig_status_not_found_e); 4027} 4028 4029ipconfig_status_t 4030get_if_option(const char * name, int option_code, void * option_data, 4031 unsigned int * option_dataCnt) 4032{ 4033 int i; 4034 boolean_t name_match; 4035 4036 for (i = 0, name_match = FALSE; 4037 i < dynarray_count(&S_ifstate_list) && name_match == FALSE; 4038 i++) { 4039 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 4040 int j; 4041 4042 if (name[0] != '\0') { 4043 if (strcmp(if_name(ifstate->if_p), name) != 0) { 4044 continue; 4045 } 4046 name_match = TRUE; 4047 } 4048 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 4049 ServiceRef service_p = dynarray_element(&ifstate->services, j); 4050 4051 if (service_get_option(service_p, option_code, option_data, 4052 option_dataCnt)) { 4053 return (ipconfig_status_success_e); 4054 } 4055 } 4056 } 4057 if (name_match == FALSE) { 4058 return (ipconfig_status_interface_does_not_exist_e); 4059 } 4060 return (ipconfig_status_not_found_e); 4061} 4062 4063ipconfig_status_t 4064get_if_packet(const char * name, void * packet_data, 4065 unsigned int * packet_dataCnt) 4066{ 4067 dhcp_info_t dhcp_info; 4068 IFStateRef ifstate; 4069 int j; 4070 4071 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, name, NULL); 4072 if (ifstate == NULL) { 4073 return (ipconfig_status_interface_does_not_exist_e); 4074 } 4075 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 4076 ServiceRef service_p = dynarray_element(&ifstate->services, j); 4077 4078 switch (service_p->method) { 4079 case ipconfig_method_inform_e: 4080 case ipconfig_method_dhcp_e: 4081 case ipconfig_method_bootp_e: 4082 if (service_p->ready == FALSE) { 4083 break; 4084 } 4085 bzero(&dhcp_info, sizeof(dhcp_info)); 4086 (void)config_method_event(service_p, IFEventID_get_dhcp_info_e, 4087 &dhcp_info); 4088 if (dhcp_info.pkt_size == 0 4089 || dhcp_info.pkt_size > *packet_dataCnt) { 4090 break; /* out of switch */ 4091 } 4092 *packet_dataCnt = dhcp_info.pkt_size; 4093 bcopy(dhcp_info.pkt, packet_data, *packet_dataCnt); 4094 return (ipconfig_status_success_e); 4095 default: 4096 break; 4097 } /* switch */ 4098 } /* for */ 4099 return (ipconfig_status_not_found_e); 4100} 4101 4102ipconfig_status_t 4103get_if_v6_packet(const char * name, void * packet_data, 4104 unsigned int * packet_dataCnt) 4105{ 4106 dhcpv6_info_t dhcp_info; 4107 IFStateRef ifstate; 4108 int j; 4109 4110 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, name, NULL); 4111 if (ifstate == NULL) { 4112 return (ipconfig_status_interface_does_not_exist_e); 4113 } 4114 for (j = 0; j < dynarray_count(&ifstate->services_v6); j++) { 4115 ServiceRef service_p = dynarray_element(&ifstate->services_v6, j); 4116 4117 switch (service_p->method) { 4118 case ipconfig_method_automatic_v6_e: 4119 case ipconfig_method_rtadv_e: 4120 if (service_p->ready == FALSE) { 4121 break; 4122 } 4123 bzero(&dhcp_info, sizeof(dhcp_info)); 4124 (void)config_method_event(service_p, IFEventID_get_dhcpv6_info_e, 4125 &dhcp_info); 4126 if (dhcp_info.pkt_len == 0 4127 || dhcp_info.pkt_len > *packet_dataCnt) { 4128 break; /* out of switch */ 4129 } 4130 *packet_dataCnt = dhcp_info.pkt_len; 4131 bcopy(dhcp_info.pkt, packet_data, *packet_dataCnt); 4132 return (ipconfig_status_success_e); 4133 default: 4134 break; 4135 } /* switch */ 4136 } /* for */ 4137 return (ipconfig_status_not_found_e); 4138} 4139 4140static IPConfigFuncRef 4141lookup_func(ipconfig_method_t method) 4142{ 4143 IPConfigFuncRef func = NULL; 4144 4145 switch (method) { 4146 case ipconfig_method_linklocal_e: 4147 func = linklocal_thread; 4148 break; 4149 case ipconfig_method_inform_e: 4150 func = inform_thread; 4151 break; 4152 case ipconfig_method_manual_e: 4153 func = manual_thread; 4154 break; 4155 case ipconfig_method_dhcp_e: 4156 func = dhcp_thread; 4157 break; 4158 case ipconfig_method_bootp_e: 4159 func = bootp_thread; 4160 break; 4161 case ipconfig_method_failover_e: 4162 func = failover_thread; 4163 break; 4164 case ipconfig_method_rtadv_e: 4165 case ipconfig_method_automatic_v6_e: 4166 if (S_configure_ipv6) { 4167 func = rtadv_thread; 4168 } 4169 break; 4170 case ipconfig_method_stf_e: 4171 if (S_configure_ipv6) { 4172 func = stf_thread; 4173 } 4174 break; 4175 case ipconfig_method_manual_v6_e: 4176 if (S_configure_ipv6) { 4177 func = manual_v6_thread; 4178 } 4179 break; 4180 case ipconfig_method_linklocal_v6_e: 4181 if (S_configure_ipv6) { 4182 func = linklocal_v6_thread; 4183 } 4184 break; 4185 default: 4186 break; 4187 } 4188 return (func); 4189} 4190 4191static ipconfig_status_t 4192config_method_start(ServiceRef service_p, ipconfig_method_t method, 4193 ipconfig_method_data_t * method_data) 4194{ 4195 IPConfigFuncRef func; 4196 interface_t * if_p = service_interface(service_p); 4197 int type = if_link_type(if_p); 4198 4199 if (method == ipconfig_method_stf_e && type != IFT_STF) { 4200 /* can't do 6to4 over anything but IFT_STF */ 4201 return (ipconfig_status_invalid_operation_e); 4202 } 4203 switch (type) { 4204 case IFT_STF: 4205 if (method != ipconfig_method_stf_e) { 4206 /* stf interface only does 6to4 */ 4207 return (ipconfig_status_invalid_operation_e); 4208 } 4209 break; 4210 case IFT_IEEE1394: 4211 if (method == ipconfig_method_bootp_e) { 4212 /* can't do BOOTP over firewire */ 4213 return (ipconfig_status_invalid_operation_e); 4214 } 4215 break; 4216 case IFT_ETHER: 4217 break; 4218 case IFT_LOOP: 4219 if (method != ipconfig_method_manual_e 4220 && method != ipconfig_method_manual_v6_e) { 4221 /* loopback interface only does MANUAL */ 4222 return (ipconfig_status_invalid_operation_e); 4223 } 4224 break; 4225 default: 4226 switch (method) { 4227 case ipconfig_method_linklocal_e: 4228 case ipconfig_method_inform_e: 4229 case ipconfig_method_dhcp_e: 4230 case ipconfig_method_bootp_e: 4231 /* can't do ARP over anything but Ethernet and FireWire */ 4232 return (ipconfig_status_invalid_operation_e); 4233 default: 4234 break; 4235 } 4236 } 4237 func = lookup_func(method); 4238 if (func == NULL) { 4239 return (ipconfig_status_operation_not_supported_e); 4240 } 4241 return (*func)(service_p, IFEventID_start_e, method_data); 4242} 4243 4244static ipconfig_status_t 4245config_method_change(ServiceRef service_p, 4246 ipconfig_method_t method, 4247 ipconfig_method_data_t * method_data, 4248 boolean_t * needs_stop) 4249{ 4250 change_event_data_t change_event; 4251 IPConfigFuncRef func; 4252 ipconfig_status_t status; 4253 4254 *needs_stop = FALSE; 4255 func = lookup_func(method); 4256 if (func == NULL) { 4257 return (ipconfig_status_operation_not_supported_e); 4258 } 4259 change_event.method_data = method_data; 4260 change_event.needs_stop = FALSE; 4261 status = (*func)(service_p, IFEventID_change_e, &change_event); 4262 *needs_stop = change_event.needs_stop; 4263 return (status); 4264} 4265 4266static ipconfig_status_t 4267config_method_event(ServiceRef service_p, IFEventID_t event, void * data) 4268{ 4269 ipconfig_status_t status = ipconfig_status_success_e; 4270 IPConfigFuncRef func; 4271 ipconfig_method_t method = service_p->method; 4272 4273 func = lookup_func(method); 4274 if (func == NULL) { 4275 my_log(LOG_ERR, 4276 "config_method_event(%s): lookup_func(%d) failed", 4277 IFEventID_names(event), method); 4278 status = ipconfig_status_internal_error_e; 4279 goto done; 4280 } 4281 (*func)(service_p, event, data); 4282 4283 done: 4284 return (status); 4285 4286} 4287 4288static ipconfig_status_t 4289config_method_stop(ServiceRef service_p) 4290{ 4291 return (config_method_event(service_p, IFEventID_stop_e, NULL)); 4292} 4293 4294static ipconfig_status_t 4295config_method_media(ServiceRef service_p, void * network_changed) 4296{ 4297 /* if there's a media event, we need to re-ARP */ 4298 service_router_clear_arp_verified(service_p); 4299 return (config_method_event(service_p, IFEventID_link_status_changed_e, 4300 network_changed)); 4301} 4302 4303static ipconfig_status_t 4304config_method_bssid_changed(ServiceRef service_p) 4305{ 4306 /* if there is a bssid change, we need to re-ARP */ 4307 service_router_clear_arp_verified(service_p); 4308 return (config_method_event(service_p, IFEventID_bssid_changed_e, 4309 NULL)); 4310 4311} 4312 4313static ipconfig_status_t 4314config_method_renew(ServiceRef service_p) 4315{ 4316 /* renew forces a re-ARP too */ 4317 service_router_clear_arp_verified(service_p); 4318 return (config_method_event(service_p, IFEventID_renew_e, NULL)); 4319} 4320 4321static void 4322service_list_event(dynarray_t * services_p, IFEventID_t event, void * data) 4323{ 4324 int i; 4325 4326 for (i = 0; i < dynarray_count(services_p); i++) { 4327 ServiceRef service_p = dynarray_element(services_p, i); 4328 4329 config_method_event(service_p, event, data); 4330 } 4331} 4332 4333static void 4334IFStateList_all_services_event(IFStateList_t * list, 4335 IFEventID_t event, void * evdata) 4336{ 4337 int i; 4338 int if_count = dynarray_count(list); 4339 4340 for (i = 0; i < if_count; i++) { 4341 IFStateRef ifstate = dynarray_element(list, i); 4342 4343 service_list_event(&ifstate->services, event, evdata); 4344 service_list_event(&ifstate->services_v6, event, evdata); 4345 } 4346 return; 4347} 4348 4349static void 4350IFStateList_all_services_sleep(IFStateList_t * list) 4351{ 4352 int i; 4353 int if_count = dynarray_count(list); 4354 4355 for (i = 0; i < if_count; i++) { 4356 IFStateRef ifstate = dynarray_element(list, i); 4357 4358 /* v4 services */ 4359 service_list_event(&ifstate->services, IFEventID_sleep_e, NULL); 4360 4361 /* v6 services */ 4362 service_list_event(&ifstate->services_v6, IFEventID_sleep_e, NULL); 4363 4364 my_CFRelease(&ifstate->neighbor_advert_list); 4365 } 4366 return; 4367} 4368 4369ipconfig_status_t 4370set_if(const char * name, ipconfig_method_t method, 4371 ipconfig_method_data_t * method_data) 4372{ 4373 interface_t * if_p = ifl_find_name(S_interfaces, name); 4374 IFStateRef ifstate; 4375 4376 if (G_IPConfiguration_verbose) { 4377 my_log(LOG_DEBUG, "set %s %s", name, ipconfig_method_string(method)); 4378 } 4379 if (if_p == NULL) { 4380 return (ipconfig_status_interface_does_not_exist_e); 4381 } 4382 ifstate = IFStateList_ifstate_create(&S_ifstate_list, if_p); 4383 if (ifstate == NULL) { 4384 return (ipconfig_status_allocation_failed_e); 4385 } 4386 /* stop existing services */ 4387 if (method == ipconfig_method_none_e 4388 || method == ipconfig_method_none_v4_e 4389 || ipconfig_method_is_v4(method)) { 4390 IFStateFreeIPv4Services(ifstate, TRUE); 4391 } 4392 else { 4393 IFStateFreeIPv6Services(ifstate, TRUE); 4394 } 4395 switch (method) { 4396 case ipconfig_method_none_e: 4397 case ipconfig_method_none_v4_e: 4398 case ipconfig_method_none_v6_e: 4399 return (ipconfig_status_success_e); 4400 default: 4401 break; 4402 } 4403 4404 /* add a new service */ 4405 return (IFState_service_add(ifstate, NULL, method, method_data, 4406 NULL, NULL)); 4407} 4408 4409static CFStringRef 4410myCFUUIDStringCreate(CFAllocatorRef alloc) 4411{ 4412 CFUUIDRef uuid; 4413 CFStringRef uuid_str; 4414 4415 uuid = CFUUIDCreate(alloc); 4416 uuid_str = CFUUIDCreateString(alloc, uuid); 4417 CFRelease(uuid); 4418 return (uuid_str); 4419} 4420 4421static ipconfig_status_t 4422add_or_set_service(const char * name, ipconfig_method_t method, 4423 bool add_only, 4424 ipconfig_method_data_t * method_data, 4425 void * service_id, unsigned int * service_id_len, 4426 CFDictionaryRef plist, pid_t pid) 4427{ 4428 interface_t * if_p = ifl_find_name(S_interfaces, name); 4429 IFStateRef ifstate; 4430 unsigned int in_length; 4431 pid_t monitor_pid = -1; 4432 int mtu = -1; 4433 boolean_t no_publish = FALSE; 4434 boolean_t perform_nud = TRUE; 4435 ServiceRef service_p; 4436 CFStringRef serviceID; 4437 ipconfig_status_t status; 4438 4439 in_length = *service_id_len; 4440 *service_id_len = 0; 4441 switch (method) { 4442 case ipconfig_method_none_e: 4443 case ipconfig_method_none_v4_e: 4444 case ipconfig_method_none_v6_e: 4445 return (ipconfig_status_invalid_parameter_e); 4446 default: 4447 break; 4448 } 4449 if (if_p == NULL) { 4450 return (ipconfig_status_interface_does_not_exist_e); 4451 } 4452 ifstate = IFStateList_ifstate_create(&S_ifstate_list, if_p); 4453 if (ifstate == NULL) { 4454 return (ipconfig_status_allocation_failed_e); 4455 } 4456 service_p = IFStateGetServiceMatchingMethod(ifstate, method, 4457 method_data, 4458 FALSE); 4459 if (service_p != NULL) { 4460 boolean_t needs_stop = FALSE; 4461 4462 if (add_only) { 4463 return (ipconfig_status_duplicate_service_e); 4464 } 4465 status = config_method_change(service_p, method, 4466 method_data, 4467 &needs_stop); 4468 if (status == ipconfig_status_success_e 4469 && needs_stop == FALSE) { 4470 return (ipconfig_status_success_e); 4471 } 4472 IFStateFreeService(ifstate, service_p); 4473 } 4474 serviceID = myCFUUIDStringCreate(NULL); 4475 if (serviceID == NULL) { 4476 return (ipconfig_status_allocation_failed_e); 4477 } 4478 4479 /* get service options */ 4480 if (plist != NULL) { 4481 CFDictionaryRef options_dict; 4482 4483 options_dict = CFDictionaryGetValue(plist, 4484 kIPConfigurationServiceOptions); 4485 if (isA_CFDictionary(options_dict) != NULL) { 4486 if (S_get_plist_boolean_quiet(options_dict, 4487 _kIPConfigurationServiceOptionMonitorPID, 4488 FALSE)) { 4489 monitor_pid = pid; 4490 } 4491 no_publish 4492 = S_get_plist_boolean_quiet(options_dict, 4493 _kIPConfigurationServiceOptionNoPublish, 4494 FALSE); 4495 mtu = S_get_plist_int_quiet(options_dict, 4496 _kIPConfigurationServiceOptionMTU, 4497 -1); 4498 perform_nud 4499 = S_get_plist_boolean_quiet(options_dict, 4500 _kIPConfigurationServiceOptionPerformNUD, 4501 TRUE); 4502 } 4503 } 4504 4505 /* add a new service */ 4506 if (G_IPConfiguration_verbose) { 4507 my_log(LOG_DEBUG, "%s %s %s", add_only ? "add_service" : "set_service", 4508 name, ipconfig_method_string(method)); 4509 } 4510 if (mtu > 0) { 4511 /* set the mtu */ 4512 my_log(LOG_DEBUG, "set interface %s mtu to %d", name, mtu); 4513 interface_set_mtu(name, mtu); 4514 } 4515 ifstate->disable_perform_nud = !perform_nud; 4516 status = IFState_service_add(ifstate, serviceID, method, method_data, 4517 NULL, &service_p); 4518 if (status == ipconfig_status_success_e) { 4519 CFIndex len; 4520 4521 service_p->is_dynamic = TRUE; 4522 service_p->no_publish = no_publish; 4523 if (monitor_pid != -1) { 4524 ServiceMonitorPID(service_p, monitor_pid); 4525 } 4526 (void)CFStringGetBytes(serviceID, 4527 CFRangeMake(0, CFStringGetLength(serviceID)), 4528 kCFStringEncodingASCII, 4529 0, FALSE, service_id, in_length, 4530 &len); 4531 *service_id_len = (int)len; 4532 } 4533 CFRelease(serviceID); 4534 return (status); 4535} 4536 4537PRIVATE_EXTERN ipconfig_status_t 4538add_service(const char * name, ipconfig_method_t method, 4539 ipconfig_method_data_t * method_data, 4540 void * service_id, unsigned int * service_id_len, 4541 CFDictionaryRef plist, pid_t pid) 4542{ 4543 return (add_or_set_service(name, method, TRUE, method_data, 4544 service_id, service_id_len, plist, pid)); 4545} 4546 4547PRIVATE_EXTERN ipconfig_status_t 4548set_service(const char * name, ipconfig_method_t method, 4549 ipconfig_method_data_t * method_data, 4550 void * service_id, unsigned int * service_id_len) 4551{ 4552 return (add_or_set_service(name, method, FALSE, method_data, 4553 service_id, service_id_len, NULL, -1)); 4554} 4555 4556STATIC ipconfig_status_t 4557S_remove_service(IFStateRef ifstate, ServiceRef service_p) 4558{ 4559 boolean_t is_ipv4; 4560 4561 is_ipv4 = ipconfig_method_is_v4(service_p->method); 4562 if (service_p->is_dynamic == FALSE) { 4563 return (ipconfig_status_invalid_operation_e); 4564 } 4565 if (G_IPConfiguration_verbose) { 4566 my_log(LOG_DEBUG, "remove_service %s %s", if_name(ifstate->if_p), 4567 ServiceGetMethodString(service_p)); 4568 } 4569 4570 /* remove the service */ 4571 IFStateFreeService(ifstate, service_p); 4572 if (is_ipv4 == FALSE 4573 && dynarray_count(&ifstate->services_v6) == 0) { 4574 (void)inet6_linklocal_stop(if_name(ifstate->if_p)); 4575 inet6_detach_interface(if_name(ifstate->if_p)); 4576 } 4577 return (ipconfig_status_success_e); 4578} 4579 4580STATIC IFStateRef 4581S_find_service_with_id(const char * ifname, CFStringRef serviceID, 4582 ServiceRef * ret_service_p) 4583{ 4584 IFStateRef ifstate; 4585 ServiceRef service_p = NULL; 4586 4587 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, ifname, NULL); 4588 if (ifstate != NULL) { 4589 service_p = IFStateGetServiceWithID(ifstate, serviceID, IS_IPV6); 4590 if (service_p == NULL) { 4591 service_p = IFStateGetServiceWithID(ifstate, serviceID, IS_IPV4); 4592 } 4593 if (service_p == NULL) { 4594 ifstate = NULL; 4595 } 4596 } 4597 *ret_service_p = service_p; 4598 return (ifstate); 4599} 4600 4601STATIC ipconfig_status_t 4602S_remove_service_with_id_str(const char * ifname, CFStringRef serviceID) 4603{ 4604 IFStateRef ifstate; 4605 ServiceRef service_p; 4606 ipconfig_status_t status; 4607 4608 if (ifname != NULL) { 4609 ifstate = S_find_service_with_id(ifname, serviceID, &service_p); 4610 } 4611 else { 4612 ifstate = IFStateListGetServiceWithID(&S_ifstate_list, 4613 serviceID, &service_p, 4614 IS_IPV6); 4615 if (ifstate == NULL) { 4616 ifstate = IFStateListGetServiceWithID(&S_ifstate_list, 4617 serviceID, &service_p, 4618 IS_IPV4); 4619 } 4620 } 4621 if (ifstate == NULL) { 4622 status = ipconfig_status_no_such_service_e; 4623 } 4624 else { 4625 status = S_remove_service(ifstate, service_p); 4626 } 4627 return (status); 4628} 4629 4630PRIVATE_EXTERN ipconfig_status_t 4631remove_service_with_id(const char * ifname, 4632 void * service_id, unsigned int service_id_len) 4633{ 4634 CFStringRef serviceID; 4635 ipconfig_status_t status; 4636 4637 serviceID = CFStringCreateWithBytes(NULL, service_id, service_id_len, 4638 kCFStringEncodingASCII, FALSE); 4639 if (serviceID == NULL) { 4640 return (ipconfig_status_allocation_failed_e); 4641 } 4642 status = S_remove_service_with_id_str(ifname, serviceID); 4643 CFRelease(serviceID); 4644 return (status); 4645} 4646 4647PRIVATE_EXTERN ipconfig_status_t 4648find_service(const char * name, boolean_t exact, 4649 ipconfig_method_t method, 4650 ipconfig_method_data_t * method_data, 4651 void * service_id, unsigned int * service_id_len) 4652{ 4653 IFStateRef ifstate; 4654 unsigned int in_length; 4655 CFIndex len = 0; 4656 ServiceRef service_p; 4657 4658 in_length = *service_id_len; 4659 *service_id_len = 0; 4660 switch (method) { 4661 case ipconfig_method_none_e: 4662 case ipconfig_method_none_v4_e: 4663 case ipconfig_method_none_v6_e: 4664 return (ipconfig_status_invalid_parameter_e); 4665 default: 4666 break; 4667 } 4668 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, name, NULL); 4669 if (ifstate == NULL) { 4670 return (ipconfig_status_interface_does_not_exist_e); 4671 } 4672 if (exact) { 4673 service_p 4674 = IFStateGetServiceWithMethod(ifstate, method, 4675 method_data, 4676 FALSE); 4677 } 4678 else { 4679 service_p 4680 = IFStateGetServiceMatchingMethod(ifstate, method, 4681 method_data, 4682 FALSE); 4683 } 4684 if (service_p == NULL) { 4685 return (ipconfig_status_no_such_service_e); 4686 } 4687 (void)CFStringGetBytes(service_p->serviceID, 4688 CFRangeMake(0, 4689 CFStringGetLength(service_p->serviceID)), 4690 kCFStringEncodingASCII, 4691 0, FALSE, service_id, in_length, 4692 &len); 4693 *service_id_len = (int)len; 4694 return (ipconfig_status_success_e); 4695} 4696 4697PRIVATE_EXTERN ipconfig_status_t 4698remove_service(const char * name, ipconfig_method_t method, 4699 ipconfig_method_data_t * method_data) 4700{ 4701 IFStateRef ifstate; 4702 ServiceRef service_p; 4703 4704 switch (method) { 4705 case ipconfig_method_none_e: 4706 case ipconfig_method_none_v4_e: 4707 case ipconfig_method_none_v6_e: 4708 return (ipconfig_status_invalid_parameter_e); 4709 default: 4710 break; 4711 } 4712 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, name, NULL); 4713 if (ifstate == NULL) { 4714 return (ipconfig_status_interface_does_not_exist_e); 4715 } 4716 service_p = IFStateGetServiceWithMethod(ifstate, method, method_data, 4717 FALSE); 4718 if (service_p == NULL) { 4719 return (ipconfig_status_no_such_service_e); 4720 } 4721 return (S_remove_service(ifstate, service_p)); 4722} 4723 4724PRIVATE_EXTERN ipconfig_status_t 4725refresh_service(const char * ifname, 4726 void * service_id, unsigned int service_id_len) 4727{ 4728 IFStateRef ifstate; 4729 CFStringRef serviceID; 4730 ServiceRef service_p; 4731 ipconfig_status_t status; 4732 4733 serviceID = CFStringCreateWithBytes(NULL, service_id, service_id_len, 4734 kCFStringEncodingASCII, FALSE); 4735 if (serviceID == NULL) { 4736 return (ipconfig_status_allocation_failed_e); 4737 } 4738 ifstate = S_find_service_with_id(ifname, serviceID, &service_p); 4739 if (ifstate == NULL) { 4740 status = ipconfig_status_no_such_service_e; 4741 } 4742 else { 4743 if (G_IPConfiguration_verbose) { 4744 my_log(LOG_DEBUG, "%s %s: refresh", 4745 if_name(ifstate->if_p), 4746 ServiceGetMethodString(service_p)); 4747 } 4748 status = config_method_event(service_p, IFEventID_renew_e, NULL); 4749 } 4750 CFRelease(serviceID); 4751 return (status); 4752} 4753 4754static boolean_t 4755ipconfig_method_from_cfstring(CFStringRef m, ipconfig_method_t * method) 4756{ 4757 if (isA_CFString(m) == NULL) { 4758 return (FALSE); 4759 } 4760 if (CFEqual(m, kSCValNetIPv4ConfigMethodBOOTP)) { 4761 *method = ipconfig_method_bootp_e; 4762 } 4763 else if (CFEqual(m, kSCValNetIPv4ConfigMethodDHCP)) { 4764 *method = ipconfig_method_dhcp_e; 4765 } 4766 else if (CFEqual(m, kSCValNetIPv4ConfigMethodManual)) { 4767 *method = ipconfig_method_manual_e; 4768 } 4769 else if (CFEqual(m, kSCValNetIPv4ConfigMethodINFORM)) { 4770 *method = ipconfig_method_inform_e; 4771 } 4772 else if (CFEqual(m, kSCValNetIPv4ConfigMethodLinkLocal)) { 4773 *method = ipconfig_method_linklocal_e; 4774 } 4775 else if (CFEqual(m, kSCValNetIPv4ConfigMethodFailover)) { 4776 *method = ipconfig_method_failover_e; 4777 } 4778 else { 4779 return (FALSE); 4780 } 4781 return (TRUE); 4782} 4783 4784static ipconfig_status_t 4785method_info_from_dict(CFDictionaryRef dict, 4786 ipconfig_method_t * ret_method, 4787 ipconfig_method_data_t * * ret_method_data) 4788{ 4789 ipconfig_method_t method = ipconfig_method_none_e; 4790 CFStringRef method_cf; 4791 ipconfig_method_data_t * method_data = NULL; 4792 int method_data_len = 0; 4793 boolean_t status = ipconfig_status_invalid_parameter_e; 4794 4795 method_cf = CFDictionaryGetValue(dict, 4796 kSCPropNetIPv4ConfigMethod); 4797 if (ipconfig_method_from_cfstring(method_cf, &method) == FALSE) { 4798 my_log(LOG_ERR, 4799 "IPConfiguration: IPv4 ConfigMethod is missing/invalid"); 4800 goto done; 4801 } 4802 if (ipconfig_method_is_manual(method)) { 4803 struct in_addr address; 4804 CFArrayRef addresses; 4805 CFStringRef address_cf; 4806 CFIndex count = 0; 4807 CFArrayRef masks; 4808 CFStringRef mask_cf = NULL; 4809 struct in_addr mask = { 0 }; 4810 4811 addresses = isA_CFArray(CFDictionaryGetValue(dict, 4812 kSCPropNetIPv4Addresses)); 4813 masks = isA_CFArray(CFDictionaryGetValue(dict, 4814 kSCPropNetIPv4SubnetMasks)); 4815 if (addresses != NULL) { 4816 count = CFArrayGetCount(addresses); 4817 } 4818 if (count == 0) { 4819 my_log(LOG_ERR, 4820 "IPConfiguration: %s Addresses missing/invalid\n", 4821 ipconfig_method_string(method)); 4822 goto done; 4823 } 4824 address_cf = CFArrayGetValueAtIndex(addresses, 0); 4825 if (my_CFStringToIPAddress(address_cf, &address) == FALSE) { 4826 my_log(LOG_ERR, 4827 "IPConfiguration: %s Addresses invalid", 4828 ipconfig_method_string(method)); 4829 goto done; 4830 } 4831 if (masks != NULL) { 4832 if (count != CFArrayGetCount(masks)) { 4833 my_log(LOG_ERR, 4834 "IPConfiguration: " 4835 "%s Addresses/SubnetMasks are different sizes", 4836 ipconfig_method_string(method)); 4837 goto done; 4838 } 4839 mask_cf = CFArrayGetValueAtIndex(masks, 0); 4840 if (my_CFStringToIPAddress(mask_cf, &mask) == FALSE) { 4841 my_log(LOG_ERR, 4842 "IPConfiguration: %s SubnetMask invalid", 4843 ipconfig_method_string(method)); 4844 goto done; 4845 } 4846 } 4847 if (count > 1) { 4848 my_log(LOG_NOTICE, 4849 "IPConfiguration: %s " 4850 "multiple addresses specified - ignoring all but first", 4851 ipconfig_method_string(method)); 4852 } 4853 method_data_len = sizeof(ipconfig_method_data_manual_t); 4854 method_data = (ipconfig_method_data_t *)malloc(method_data_len); 4855 if (method_data == NULL) { 4856 my_log(LOG_ERR, "IPConfiguration: malloc method_data failed"); 4857 status = ipconfig_status_allocation_failed_e; 4858 goto done; 4859 } 4860 bzero(method_data, method_data_len); 4861 method_data->manual.addr = address; 4862 method_data->manual.mask = mask; 4863 if (method == ipconfig_method_manual_e) { 4864 CFBooleanRef b; 4865 CFStringRef router = NULL; 4866 4867 b = isA_CFBoolean(CFDictionaryGetValue(dict, 4868 kSCPropNetIgnoreLinkStatus)); 4869 method_data->manual.ignore_link_status 4870 = (b != NULL) ? CFBooleanGetValue(b) : FALSE; 4871 router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router); 4872 if (router != NULL 4873 && my_CFStringToIPAddress(router, &method_data->manual.router) 4874 == FALSE) { 4875 my_log(LOG_NOTICE, 4876 "IPConfiguration: %s Router invalid", 4877 ipconfig_method_string(method)); 4878 } 4879 } 4880 else if (method == ipconfig_method_failover_e) { 4881 CFNumberRef num; 4882 4883 num = CFDictionaryGetValue(dict, 4884 kSCPropNetIPv4FailoverAddressTimeout); 4885 if (num != NULL 4886 && (isA_CFNumber(num) == NULL 4887 || (CFNumberGetValue(num, kCFNumberSInt32Type, 4888 &method_data->manual.failover_timeout) 4889 == FALSE))) { 4890 my_log(LOG_NOTICE, 4891 "IPConfiguration: FailoverAddressTimeout invalid"); 4892 } 4893 } 4894 } 4895 else if (method == ipconfig_method_dhcp_e) { 4896 char cid[255]; 4897 int cid_len = 0; 4898 CFStringRef client_id = NULL; 4899 4900 client_id = CFDictionaryGetValue(dict, kSCPropNetIPv4DHCPClientID); 4901 if (isA_CFString(client_id) != NULL) { 4902 cid_len = my_CFStringToCStringAndLength(client_id, cid, sizeof(cid)); 4903 } 4904 if (cid_len != 0) { 4905 cid_len--; /* we don't want the trailing nul character */ 4906 method_data_len = offsetof(ipconfig_method_data_dhcp_t, client_id) 4907 + cid_len; 4908 } 4909 if (method_data_len > 0) { 4910 method_data = (ipconfig_method_data_t *)malloc(method_data_len); 4911 if (method_data == NULL) { 4912 my_log(LOG_ERR, "IPConfiguration: malloc DHCPClientID failed"); 4913 status = ipconfig_status_allocation_failed_e; 4914 goto done; 4915 } 4916 method_data->dhcp.client_id_len = cid_len; 4917 bcopy(cid, method_data->dhcp.client_id, cid_len); 4918 } 4919 } 4920 status = ipconfig_status_success_e; 4921 4922 done: 4923 *ret_method_data = method_data; 4924 *ret_method = method; 4925 return (status); 4926} 4927 4928static boolean_t 4929ipconfig_method_from_cfstring_ipv6(CFStringRef m, ipconfig_method_t * method) 4930{ 4931 if (isA_CFString(m) == NULL) { 4932 return (FALSE); 4933 } 4934 if (CFEqual(m, kSCValNetIPv6ConfigMethodManual)) { 4935 *method = ipconfig_method_manual_v6_e; 4936 } 4937 else if (CFEqual(m, kSCValNetIPv6ConfigMethodAutomatic)) { 4938 *method = ipconfig_method_automatic_v6_e; 4939 } 4940 else if (CFEqual(m, kSCValNetIPv6ConfigMethodRouterAdvertisement)) { 4941 *method = ipconfig_method_rtadv_e; 4942 } 4943 else if (CFEqual(m, kSCValNetIPv6ConfigMethod6to4)) { 4944 *method = ipconfig_method_stf_e; 4945 } 4946 else if (CFEqual(m, kSCValNetIPv6ConfigMethodLinkLocal)) { 4947 *method = ipconfig_method_linklocal_v6_e; 4948 } 4949 else { 4950 return (FALSE); 4951 } 4952 return (TRUE); 4953} 4954 4955STATIC bool 4956my_CFStringToIPv6Address(CFStringRef str, struct in6_addr * ret_ip) 4957{ 4958 char buf[64]; 4959 4960 if (isA_CFString(str) == NULL) { 4961 return (FALSE); 4962 } 4963 if (CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingASCII) 4964 == FALSE) { 4965 return (FALSE); 4966 } 4967 if (inet_pton(AF_INET6, buf, ret_ip) == 1) { 4968 return (TRUE); 4969 } 4970 return (FALSE); 4971} 4972 4973static ipconfig_status_t 4974method_info_from_ipv6_dict(CFDictionaryRef dict, 4975 ipconfig_method_t * ret_method, 4976 ipconfig_method_data_t * * ret_method_data) 4977{ 4978 ipconfig_method_t method = ipconfig_method_none_v6_e; 4979 CFStringRef method_cf; 4980 ipconfig_method_data_t * method_data = NULL; 4981 int method_data_len = 0; 4982 boolean_t status = ipconfig_status_invalid_parameter_e; 4983 4984 method_cf = CFDictionaryGetValue(dict, 4985 kSCPropNetIPv6ConfigMethod); 4986 if (ipconfig_method_from_cfstring_ipv6(method_cf, &method) == FALSE) { 4987 my_log(LOG_ERR, 4988 "IPConfiguration: IPv6 ConfigMethod is missing/invalid"); 4989 goto done; 4990 } 4991 if (method == ipconfig_method_manual_v6_e) { 4992 struct in6_addr address; 4993 CFArrayRef addresses; 4994 CFStringRef address_cf; 4995 CFIndex count = 0; 4996 CFArrayRef prefixes; 4997 CFNumberRef prefix_cf = NULL; 4998 int prefix = 0; 4999 5000 addresses 5001 = isA_CFArray(CFDictionaryGetValue(dict, kSCPropNetIPv6Addresses)); 5002 prefixes 5003 = isA_CFArray(CFDictionaryGetValue(dict, 5004 kSCPropNetIPv6PrefixLength)); 5005 if (addresses != NULL) { 5006 count = CFArrayGetCount(addresses); 5007 } 5008 if (count == 0) { 5009 my_log(LOG_ERR, 5010 "IPConfiguration: %s Addresses missing/invalid\n", 5011 ipconfig_method_string(method)); 5012 goto done; 5013 } 5014 address_cf = CFArrayGetValueAtIndex(addresses, 0); 5015 if (my_CFStringToIPv6Address(address_cf, &address) == FALSE) { 5016 my_log(LOG_ERR, 5017 "IPConfiguration: %s Addresses invalid", 5018 ipconfig_method_string(method)); 5019 goto done; 5020 } 5021 if (IN6_IS_ADDR_LINKLOCAL(&address)) { 5022 my_log(LOG_ERR, 5023 "IPConfiguration: %s cannot configure IPv6 Link Local address", 5024 ipconfig_method_string(method)); 5025 goto done; 5026 } 5027 if (prefixes != NULL) { 5028 if (count != CFArrayGetCount(prefixes)) { 5029 my_log(LOG_ERR, 5030 "IPConfiguration: " 5031 "%s Addresses/PrefixLength are different sizes", 5032 ipconfig_method_string(method)); 5033 goto done; 5034 } 5035 prefix_cf = CFArrayGetValueAtIndex(prefixes, 0); 5036 if (isA_CFNumber(prefix_cf) == NULL 5037 || (CFNumberGetValue(prefix_cf, kCFNumberIntType, &prefix) 5038 == FALSE)) { 5039 my_log(LOG_ERR, "IPConfiguration: %s PrefixLength invalid", 5040 ipconfig_method_string(method)); 5041 goto done; 5042 } 5043 } 5044 if (count > 1) { 5045 my_log(LOG_NOTICE, 5046 "IPConfiguration: %s " 5047 "multiple addresses specified - ignoring all but first", 5048 ipconfig_method_string(method)); 5049 } 5050 method_data_len = sizeof(ipconfig_method_data_manual_v6_t); 5051 method_data = (ipconfig_method_data_t *)malloc(method_data_len); 5052 if (method_data == NULL) { 5053 my_log(LOG_ERR, "IPConfiguration: malloc method_data failed"); 5054 status = ipconfig_status_allocation_failed_e; 5055 goto done; 5056 } 5057 bzero(method_data, method_data_len); 5058 method_data->manual_v6.addr = address; 5059 method_data->manual_v6.prefix_length = prefix; 5060 } 5061 else if (method == ipconfig_method_stf_e) { 5062 CFStringRef relay_cf; 5063 5064 relay_cf = CFDictionaryGetValue(dict, kSCPropNetIPv66to4Relay); 5065 if (relay_cf != NULL) { 5066 char buf[256]; 5067 int len; 5068 address_type_t relay_addr_type; 5069 struct in_addr relay_ip; 5070 struct in6_addr relay_ipv6; 5071 5072 if (isA_CFString(relay_cf) == NULL) { 5073 my_log(LOG_ERR, "IPConfiguration: %s 6to4 Relay invalid", 5074 ipconfig_method_string(method)); 5075 goto done; 5076 } 5077 len = my_CFStringToCStringAndLength(relay_cf, buf, sizeof(buf)); 5078 if (len == 0) { 5079 my_log(LOG_ERR, "IPConfiguration: %s 6to4 Relay empty", 5080 ipconfig_method_string(method)); 5081 goto done; 5082 } 5083 if (inet_aton(buf, &relay_ip) == 1) { 5084 relay_addr_type = address_type_ipv4_e; 5085 method_data_len = sizeof(ipconfig_method_data_stf_t); 5086 } 5087 else if (inet_pton(AF_INET6, buf, &relay_ipv6) == 1) { 5088 relay_addr_type = address_type_ipv6_e; 5089 method_data_len = sizeof(ipconfig_method_data_stf_t); 5090 } 5091 else { 5092 relay_addr_type = address_type_dns_e; 5093 method_data_len = offsetof(ipconfig_method_data_stf_t, 5094 relay_addr.dns) + len + 1; 5095 } 5096 method_data = (ipconfig_method_data_t *)malloc(method_data_len); 5097 if (method_data == NULL) { 5098 my_log(LOG_ERR, "IPConfiguration: malloc method_data failed"); 5099 status = ipconfig_status_allocation_failed_e; 5100 goto done; 5101 } 5102 method_data->stf.relay_addr_type = relay_addr_type; 5103 switch (relay_addr_type) { 5104 case address_type_ipv4_e: 5105 method_data->stf.relay_addr.v4 = relay_ip; 5106 break; 5107 case address_type_ipv6_e: 5108 method_data->stf.relay_addr.v6 = relay_ipv6; 5109 break; 5110 case address_type_dns_e: 5111 default: 5112 bcopy(buf, method_data->stf.relay_addr.dns, len); 5113 method_data->stf.relay_addr.dns[len] = '\0'; 5114 break; 5115 } 5116 } 5117 } 5118 status = ipconfig_status_success_e; 5119 5120 done: 5121 *ret_method_data = method_data; 5122 *ret_method = method; 5123 return (status); 5124} 5125 5126static CFArrayRef 5127get_order_array_from_values(CFDictionaryRef values, CFStringRef order_key) 5128{ 5129 CFDictionaryRef dict; 5130 CFArrayRef order_array = NULL; 5131 5132 dict = isA_CFDictionary(CFDictionaryGetValue(values, order_key)); 5133 if (dict) { 5134 order_array = CFDictionaryGetValue(dict, 5135 kSCPropNetServiceOrder); 5136 order_array = isA_CFArray(order_array); 5137 if (order_array && CFArrayGetCount(order_array) == 0) { 5138 order_array = NULL; 5139 } 5140 } 5141 return (order_array); 5142} 5143 5144#define ARBITRARILY_LARGE_NUMBER (1000 * 1000) 5145 5146static int 5147lookup_order(CFArrayRef order, CFStringRef serviceID) 5148{ 5149 CFIndex count; 5150 int i; 5151 5152 if (order == NULL) 5153 goto done; 5154 5155 count = CFArrayGetCount(order); 5156 for (i = 0; i < count; i++) { 5157 CFStringRef sid = CFArrayGetValueAtIndex(order, i); 5158 5159 if (CFEqual(sid, serviceID)) 5160 return (i); 5161 } 5162 done: 5163 return (ARBITRARILY_LARGE_NUMBER); 5164} 5165 5166static CFComparisonResult 5167compare_serviceIDs(const void *val1, const void *val2, void *context) 5168{ 5169 CFArrayRef order_array = (CFArrayRef)context; 5170 int rank1; 5171 int rank2; 5172 5173 rank1 = lookup_order(order_array, (CFStringRef)val1); 5174 rank2 = lookup_order(order_array, (CFStringRef)val2); 5175 if (rank1 == rank2) 5176 return (kCFCompareEqualTo); 5177 if (rank1 < rank2) 5178 return (kCFCompareLessThan); 5179 return (kCFCompareGreaterThan); 5180} 5181 5182static CFDictionaryRef 5183copy_ipv4_service_dict(CFDictionaryRef values, CFStringRef serviceID, 5184 CFStringRef type, CFStringRef ifn_cf) 5185{ 5186 CFDictionaryRef dict; 5187 CFStringRef key; 5188 CFMutableDictionaryRef service_dict; 5189 5190 if (CFEqual(type, kSCValNetInterfaceTypeEthernet) == FALSE 5191 && CFEqual(type, kSCValNetInterfaceTypeFireWire) == FALSE 5192 && CFEqual(type, kSCValNetInterfaceTypeLoopback) == FALSE) { 5193 /* we only configure ethernet/firewire/loopback interfaces currently */ 5194 return (NULL); 5195 } 5196 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5197 kSCDynamicStoreDomainSetup, 5198 serviceID, 5199 kSCEntNetIPv4); 5200 dict = CFDictionaryGetValue(values, key); 5201 CFRelease(key); 5202 if (isA_CFDictionary(dict) == NULL) { 5203 return (NULL); 5204 } 5205 /* return IPv4 dict annotated with interface name and serviceID */ 5206 service_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 5207 CFDictionarySetValue(service_dict, kSCPropNetInterfaceDeviceName, 5208 ifn_cf); 5209 CFDictionarySetValue(service_dict, PROP_SERVICEID, serviceID); 5210 return (service_dict); 5211} 5212 5213static CFDictionaryRef 5214copy_ipv6_service_dict(CFDictionaryRef values, CFStringRef serviceID, 5215 CFStringRef type, CFStringRef ifn_cf) 5216{ 5217 CFDictionaryRef dict; 5218 CFStringRef key; 5219 CFMutableDictionaryRef service_dict; 5220 5221 if (CFEqual(type, kSCValNetInterfaceTypeEthernet) == FALSE 5222 && CFEqual(type, kSCValNetInterfaceTypeFireWire) == FALSE 5223 && CFEqual(type, kSCValNetInterfaceType6to4) == FALSE 5224 && CFEqual(type, kSCValNetInterfaceTypeLoopback) == FALSE) { 5225 /* we only configure ethernet/firewire/6to4/loopback interfaces currently */ 5226 return (NULL); 5227 } 5228 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5229 kSCDynamicStoreDomainSetup, 5230 serviceID, 5231 kSCEntNetIPv6); 5232 dict = CFDictionaryGetValue(values, key); 5233 CFRelease(key); 5234 5235 if (isA_CFDictionary(dict) == NULL) { 5236 return (NULL); 5237 } 5238 /* return IPv6 dict annotated with interface name, serviceID, 6to4Relay */ 5239 service_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 5240 CFDictionarySetValue(service_dict, kSCPropNetInterfaceDeviceName, 5241 ifn_cf); 5242 CFDictionarySetValue(service_dict, PROP_SERVICEID, serviceID); 5243 5244 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5245 kSCDynamicStoreDomainSetup, 5246 serviceID, 5247 kSCEntNet6to4); 5248 dict = CFDictionaryGetValue(values, key); 5249 CFRelease(key); 5250 if (isA_CFDictionary(dict) != NULL) { 5251 CFStringRef stf_relay; 5252 5253 stf_relay = CFDictionaryGetValue(dict, kSCPropNet6to4Relay); 5254 if (stf_relay != NULL) { 5255 CFDictionarySetValue(service_dict, 5256 kSCPropNetIPv66to4Relay, 5257 stf_relay); 5258 } 5259 } 5260 return (service_dict); 5261} 5262 5263static CFArrayRef 5264copy_serviceIDs_from_values(CFDictionaryRef values, CFArrayRef order_array) 5265{ 5266 CFIndex count; 5267 int i; 5268 const void * * keys; 5269 CFMutableArrayRef list = NULL; 5270 CFIndex list_count; 5271 5272 /* if there are no values, we're done */ 5273 count = CFDictionaryGetCount(values); 5274 if (count == 0) { 5275 return (NULL); 5276 } 5277 list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5278 keys = (const void * *)malloc(sizeof(*keys) * count); 5279 CFDictionaryGetKeysAndValues(values, (const void * *)keys, NULL); 5280 for (i = 0; i < count; i++) { 5281 CFStringRef serviceID; 5282 5283 if (CFStringHasPrefix(keys[i], S_setup_service_prefix) == FALSE) { 5284 continue; 5285 } 5286 /* Setup:/Network/Service/<serviceID>/{IPv4,[IPv6,]Interface} */ 5287 serviceID = my_CFStringCopyComponent(keys[i], CFSTR("/"), 3); 5288 if (serviceID == NULL) { 5289 continue; 5290 } 5291 my_CFArrayAppendUniqueValue(list, serviceID); 5292 CFRelease(serviceID); 5293 } 5294 free(keys); 5295 list_count = CFArrayGetCount(list); 5296 if (list_count == 0) { 5297 my_CFRelease(&list); 5298 } 5299 else if (order_array != NULL) { 5300 /* sort the list according to the defined service order */ 5301 CFArraySortValues(list, CFRangeMake(0, list_count), 5302 compare_serviceIDs, (void *)order_array); 5303 } 5304 return (list); 5305} 5306 5307static CFArrayRef 5308entity_all(SCDynamicStoreRef session, CFArrayRef * ret_ipv6_services) 5309{ 5310 CFMutableArrayRef all_services = NULL; 5311 CFMutableArrayRef all_v6_services = NULL; 5312 CFMutableArrayRef get_keys = NULL; 5313 CFMutableArrayRef get_patterns = NULL; 5314 int i; 5315 CFStringRef key = NULL; 5316 CFArrayRef service_IDs = NULL; 5317 CFIndex service_IDs_count; 5318 CFStringRef order_key = NULL; 5319 CFArrayRef order_array = NULL; 5320 CFDictionaryRef values = NULL; 5321 5322 get_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5323 get_patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5324 all_services = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5325 all_v6_services = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5326 5327 /* get Setup:/Network/Service/any/{IPv4,[ IPv6,] Interface} */ 5328 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5329 kSCDynamicStoreDomainSetup, 5330 kSCCompAnyRegex, 5331 kSCEntNetIPv4); 5332 CFArrayAppendValue(get_patterns, key); 5333 CFRelease(key); 5334 5335 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5336 kSCDynamicStoreDomainSetup, 5337 kSCCompAnyRegex, 5338 kSCEntNetIPv6); 5339 CFArrayAppendValue(get_patterns, key); 5340 CFRelease(key); 5341 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5342 kSCDynamicStoreDomainSetup, 5343 kSCCompAnyRegex, 5344 kSCEntNet6to4); 5345 CFArrayAppendValue(get_patterns, key); 5346 CFRelease(key); 5347 5348 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5349 kSCDynamicStoreDomainSetup, 5350 kSCCompAnyRegex, 5351 kSCEntNetInterface); 5352 CFArrayAppendValue(get_patterns, key); 5353 CFRelease(key); 5354 5355 /* populate keys array to get Setup:/Network/Global/IPv4 */ 5356 order_key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 5357 kSCDynamicStoreDomainSetup, 5358 kSCEntNetIPv4); 5359 CFArrayAppendValue(get_keys, order_key); 5360 5361 /* get keys and values atomically */ 5362 values = SCDynamicStoreCopyMultiple(session, get_keys, get_patterns); 5363 if (values == NULL) { 5364 goto done; 5365 } 5366 5367 /* grab the service order array */ 5368 order_array = get_order_array_from_values(values, order_key); 5369 5370 /* build a list of configured service ID's */ 5371 service_IDs = copy_serviceIDs_from_values(values, order_array); 5372 if (service_IDs == NULL) { 5373 /* if there are no serviceIDs, we're done */ 5374 goto done; 5375 } 5376 5377 /* populate all_services array with annotated IPv4[/IPv6] dict's */ 5378 service_IDs_count = CFArrayGetCount(service_IDs); 5379 for (i = 0; i < service_IDs_count; i++) { 5380 CFStringRef key; 5381 CFDictionaryRef if_dict; 5382 CFStringRef ifname; 5383 CFDictionaryRef service_dict = NULL; 5384 CFStringRef serviceID; 5385 CFStringRef type; 5386 5387 serviceID = CFArrayGetValueAtIndex(service_IDs, i); 5388 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5389 kSCDynamicStoreDomainSetup, 5390 serviceID, 5391 kSCEntNetInterface); 5392 if_dict = CFDictionaryGetValue(values, key); 5393 CFRelease(key); 5394 if_dict = isA_CFDictionary(if_dict); 5395 if (if_dict == NULL) { 5396 continue; 5397 } 5398 type = CFDictionaryGetValue(if_dict, kSCPropNetInterfaceType); 5399 if (isA_CFString(type) == NULL) { 5400 my_log(LOG_NOTICE, 5401 "IPConfiguration: Interface Type missing/invalid" 5402 "\nInterface = %@", if_dict); 5403 continue; 5404 } 5405 ifname = CFDictionaryGetValue(if_dict, kSCPropNetInterfaceDeviceName); 5406 if (isA_CFString(ifname) == NULL) { 5407 continue; 5408 } 5409 5410 /* get IPv4 service configuration */ 5411 service_dict = copy_ipv4_service_dict(values, serviceID, 5412 type, ifname); 5413 if (service_dict != NULL) { 5414 CFArrayAppendValue(all_services, service_dict); 5415 CFRelease(service_dict); 5416 } 5417 /* get IPv6 service configuration */ 5418 service_dict = copy_ipv6_service_dict(values, serviceID, 5419 type, ifname); 5420 if (service_dict != NULL) { 5421 CFArrayAppendValue(all_v6_services, service_dict); 5422 CFRelease(service_dict); 5423 } 5424 } 5425 5426 done: 5427 my_CFRelease(&values); 5428 my_CFRelease(&order_key); 5429 my_CFRelease(&get_keys); 5430 my_CFRelease(&get_patterns); 5431 my_CFRelease(&service_IDs); 5432 if (all_services != NULL && CFArrayGetCount(all_services) == 0) { 5433 my_CFRelease(&all_services); 5434 } 5435 if (all_v6_services != NULL && CFArrayGetCount(all_v6_services) == 0) { 5436 my_CFRelease(&all_v6_services); 5437 } 5438 *ret_ipv6_services = all_v6_services; 5439 return (all_services); 5440} 5441 5442 5443static CFDictionaryRef 5444lookup_entity(CFArrayRef all, CFStringRef ifn_cf) 5445{ 5446 CFIndex count; 5447 int i; 5448 5449 if (all == NULL) 5450 return (NULL); 5451 5452 count = CFArrayGetCount(all); 5453 for (i = 0; i < count; i++) { 5454 CFDictionaryRef item = CFArrayGetValueAtIndex(all, i); 5455 CFStringRef name; 5456 5457 name = CFDictionaryGetValue(item, kSCPropNetInterfaceDeviceName); 5458 if (CFEqual(name, ifn_cf)) { 5459 return (item); 5460 } 5461 } 5462 return (NULL); 5463} 5464 5465static CFArrayRef 5466interface_services_copy(CFArrayRef all, CFStringRef ifn_cf) 5467{ 5468 CFIndex count; 5469 int i; 5470 CFMutableArrayRef list = NULL; 5471 5472 if (all == NULL) { 5473 return (NULL); 5474 } 5475 5476 list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5477 if (list == NULL) { 5478 return (NULL); 5479 } 5480 count = CFArrayGetCount(all); 5481 for (i = 0; i < count; i++) { 5482 CFDictionaryRef item = CFArrayGetValueAtIndex(all, i); 5483 CFStringRef name; 5484 5485 name = CFDictionaryGetValue(item, kSCPropNetInterfaceDeviceName); 5486 if (CFEqual(name, ifn_cf)) { 5487 CFArrayAppendValue(list, item); 5488 } 5489 } 5490 if (CFArrayGetCount(list) == 0) { 5491 my_CFRelease(&list); 5492 } 5493 return (list); 5494} 5495 5496typedef struct { 5497 CFStringRef serviceID; 5498 ipconfig_method_t method; 5499 ipconfig_method_data_t * method_data; 5500} ServiceConfig, * ServiceConfigRef; 5501 5502typedef struct { 5503 ServiceConfigRef list; 5504 int count; 5505 boolean_t is_ipv4; 5506} ServiceConfigList, * ServiceConfigListRef; 5507 5508static void 5509ServiceConfigListFree(ServiceConfigListRef scl) 5510{ 5511 int i; 5512 ServiceConfigRef scan; 5513 5514 if (scl->list == NULL) { 5515 return; 5516 } 5517 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5518 my_CFRelease(&scan->serviceID); 5519 if (scan->method_data != NULL) { 5520 free(scan->method_data); 5521 } 5522 } 5523 free(scl->list); 5524 scl->list = NULL; 5525 return; 5526} 5527 5528#ifdef DEBUG 5529void 5530ServiceConfigListPrint(ServiceConfigListRef scl) 5531{ 5532 int i; 5533 ServiceConfigRef scan; 5534 5535 my_log(LOG_DEBUG, 5536 "%d %s configs\n", scl->count, scl->is_ipv4 ? "IPv4" : "IPv6"); 5537 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5538 my_log(LOG_DEBUG, "serviceID %@ %s Data %p", 5539 scan->serviceID, 5540 ipconfig_method_string(scan->method), 5541 scan->method_data); 5542 if (scan->method_data != NULL 5543 && scan->method == ipconfig_method_stf_e) { 5544 char ntopbuf[INET6_ADDRSTRLEN]; 5545 ipconfig_method_data_stf_t * stf; 5546 5547 stf = &scan->method_data->stf; 5548 switch (stf->relay_addr_type) { 5549 case address_type_ipv4_e: 5550 my_log(LOG_DEBUG, "IPv4 relay " IP_FORMAT, 5551 IP_LIST(&stf->relay_addr.v4)); 5552 break; 5553 case address_type_ipv6_e: 5554 my_log(LOG_DEBUG, "IPv6 relay %s", 5555 inet_ntop(AF_INET6, &stf->relay_addr.v6, 5556 ntopbuf, sizeof(ntopbuf))); 5557 break; 5558 case address_type_dns_e: 5559 my_log(LOG_DEBUG, "DNS relay %s", stf->relay_addr.dns); 5560 break; 5561 default: 5562 my_log(LOG_DEBUG, "Bogus relay type %d", stf->relay_addr_type); 5563 break; 5564 } 5565 } 5566 } 5567} 5568#endif /* DEBUG */ 5569 5570static ServiceConfigRef 5571ServiceConfigListLookupMethod(ServiceConfigListRef scl, 5572 ipconfig_method_t method, 5573 ipconfig_method_data_t * method_data) 5574{ 5575 int i; 5576 ServiceConfigRef scan; 5577 5578 switch (method) { 5579 case ipconfig_method_stf_e: 5580 case ipconfig_method_linklocal_e: 5581 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5582 if (method == scan->method) { 5583 return (scan); 5584 } 5585 } 5586 break; 5587 case ipconfig_method_rtadv_e: 5588 case ipconfig_method_automatic_v6_e: 5589 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5590 switch (scan->method) { 5591 case ipconfig_method_rtadv_e: 5592 case ipconfig_method_automatic_v6_e: 5593 return (scan); 5594 default: 5595 break; 5596 } 5597 } 5598 break; 5599 case ipconfig_method_dhcp_e: 5600 case ipconfig_method_bootp_e: 5601 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5602 if (ipconfig_method_is_dhcp_or_bootp(scan->method)) 5603 return (scan); 5604 } 5605 break; 5606 case ipconfig_method_failover_e: 5607 case ipconfig_method_manual_e: 5608 case ipconfig_method_inform_e: 5609 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5610 if (ipconfig_method_is_manual(scan->method) 5611 && (method_data->manual.addr.s_addr 5612 == scan->method_data->manual.addr.s_addr)) { 5613 return (scan); 5614 } 5615 } 5616 break; 5617 case ipconfig_method_manual_v6_e: 5618 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5619 if (scan->method != ipconfig_method_manual_v6_e) { 5620 continue; 5621 } 5622 if (IN6_ARE_ADDR_EQUAL(&method_data->manual_v6.addr, 5623 &scan->method_data->manual_v6.addr)) { 5624 return (scan); 5625 } 5626 } 5627 break; 5628 default: 5629 break; 5630 } 5631 return (NULL); 5632} 5633 5634static ServiceConfigRef 5635ServiceConfigListLookupService(ServiceConfigListRef scl, CFStringRef serviceID) 5636{ 5637 int i; 5638 ServiceConfigRef scan; 5639 5640 for (i = 0, scan = scl->list; i < scl->count; i++, scan++) { 5641 if (CFEqual(serviceID, scan->serviceID)) { 5642 return (scan); 5643 } 5644 } 5645 return (NULL); 5646} 5647 5648static ServiceRef 5649find_dynamic_service(const char * ifname, ipconfig_method_t method, 5650 ipconfig_method_data_t * method_data) 5651{ 5652 interface_t * if_p = ifl_find_name(S_interfaces, ifname); 5653 IFStateRef ifstate = NULL; 5654 5655 if (if_p == NULL) { 5656 return (NULL); 5657 } 5658 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, ifname, NULL); 5659 if (ifstate == NULL) { 5660 return (NULL); 5661 } 5662 return (IFStateGetServiceMatchingMethod(ifstate, method, 5663 method_data, TRUE)); 5664} 5665 5666static boolean_t 5667ServiceConfigListInit(ServiceConfigListRef scl, boolean_t is_ipv4, 5668 CFArrayRef all_services, const char * ifname) 5669{ 5670 int i; 5671 CFArrayRef if_service_list; 5672 CFIndex if_service_count; 5673 CFStringRef ifn_cf = NULL; 5674 boolean_t ret; 5675 5676 bzero(scl, sizeof(*scl)); 5677 scl->is_ipv4 = is_ipv4; 5678 ifn_cf = CFStringCreateWithCString(NULL, ifname, 5679 kCFStringEncodingASCII); 5680 if_service_list = interface_services_copy(all_services, ifn_cf); 5681 if (if_service_list == NULL) { 5682 goto done; 5683 } 5684 if_service_count = CFArrayGetCount(if_service_list); 5685 scl->list = (ServiceConfigRef)malloc(if_service_count * sizeof(*scl->list)); 5686 if (scl->list == NULL) { 5687 goto done; 5688 } 5689 for (i = 0; i < if_service_count; i++) { 5690 boolean_t duplicate_config = FALSE; 5691 boolean_t duplicate_dynamic = FALSE; 5692 ipconfig_method_t method; 5693 ipconfig_method_data_t *method_data = NULL; 5694 CFDictionaryRef service_dict; 5695 CFStringRef serviceID; 5696 5697 service_dict = CFArrayGetValueAtIndex(if_service_list, i); 5698 if (is_ipv4) { 5699 if (method_info_from_dict(service_dict, &method, &method_data) 5700 != ipconfig_status_success_e) { 5701 continue; 5702 } 5703 } 5704 else { 5705 if (method_info_from_ipv6_dict(service_dict, &method, &method_data) 5706 != ipconfig_status_success_e) { 5707 continue; 5708 } 5709 } 5710 duplicate_config 5711 = (ServiceConfigListLookupMethod(scl, method, method_data) != NULL); 5712 if (duplicate_config == FALSE) { 5713 duplicate_dynamic = (find_dynamic_service(ifname, method, 5714 method_data) != NULL); 5715 } 5716 if (duplicate_config || duplicate_dynamic) { 5717 my_log(LOG_NOTICE, "%s: %s %s", 5718 ifname, ipconfig_method_string(method), 5719 duplicate_config 5720 ? "duplicate configured service" 5721 : "configured service conflicts with dynamic service"); 5722 free(method_data); 5723 continue; 5724 } 5725 serviceID = CFDictionaryGetValue(service_dict, PROP_SERVICEID); 5726 scl->list[scl->count].serviceID = CFRetain(serviceID); 5727 scl->list[scl->count].method = method; 5728 scl->list[scl->count].method_data = method_data; 5729 scl->count++; 5730 } 5731 done: 5732 if (scl->count == 0) { 5733 ServiceConfigListFree(scl); 5734 ret = FALSE; 5735 } 5736 else { 5737 ret = TRUE; 5738 } 5739 my_CFRelease(&ifn_cf); 5740 my_CFRelease(&if_service_list); 5741 return (ret); 5742} 5743 5744static void 5745ServiceConfigListFreeInactiveServices(ServiceConfigListRef scl, 5746 const char * ifname) 5747{ 5748 CFMutableArrayRef inactive_list = NULL; 5749 CFIndex inactive_list_count; 5750 int i; 5751 IFStateRef ifstate; 5752 dynarray_t * list; 5753 5754 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, ifname, NULL); 5755 if (ifstate == NULL) { 5756 return; 5757 } 5758 if (scl->is_ipv4) { 5759 list = &ifstate->services; 5760 } 5761 else { 5762 list = &ifstate->services_v6; 5763 } 5764 inactive_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5765 if (inactive_list == NULL) { 5766 return; 5767 } 5768 for (i = 0; i < dynarray_count(list); i++) { 5769 ServiceRef service_p = dynarray_element(list, i); 5770 CFStringRef serviceID = service_p->serviceID; 5771 5772 if (service_p->is_dynamic) { 5773 /* dynamically created services survive configuration changes */ 5774 continue; 5775 } 5776 if (service_p->parent_serviceID != NULL) { 5777 /* this service gets cleaned up on its own */ 5778 continue; 5779 } 5780 if (ServiceConfigListLookupService(scl, serviceID) == NULL) { 5781 CFArrayAppendValue(inactive_list, serviceID); 5782 } 5783 } 5784 inactive_list_count = CFArrayGetCount(inactive_list); 5785 for (i = 0; i < inactive_list_count; i++) { 5786 CFStringRef serviceID = CFArrayGetValueAtIndex(inactive_list, i); 5787 5788 IFStateFreeServiceWithID(ifstate, serviceID, scl->is_ipv4); 5789 } 5790 my_CFRelease(&inactive_list); 5791 return; 5792} 5793 5794static ipconfig_status_t 5795S_set_service(IFStateRef ifstate, ServiceConfigRef config, boolean_t is_ipv4) 5796{ 5797 CFStringRef serviceID = config->serviceID; 5798 ServiceRef service_p; 5799 IFStateRef this_ifstate = NULL; 5800 5801 service_p = IFStateGetServiceWithID(ifstate, serviceID, is_ipv4); 5802 if (service_p != NULL) { 5803 boolean_t needs_stop = FALSE; 5804 ipconfig_status_t status; 5805 5806 if (service_p->method == config->method) { 5807 status = config_method_change(service_p, config->method, 5808 config->method_data, 5809 &needs_stop); 5810 if (status == ipconfig_status_success_e 5811 && needs_stop == FALSE) { 5812 return (ipconfig_status_success_e); 5813 } 5814 } 5815 IFStateFreeService(ifstate, service_p); 5816 } 5817 else { 5818 this_ifstate = IFStateListGetServiceWithID(&S_ifstate_list, 5819 serviceID, 5820 &service_p, 5821 is_ipv4); 5822 if (this_ifstate) { 5823 /* service is on other interface, stop it now */ 5824 IFStateFreeService(this_ifstate, service_p); 5825 } 5826 } 5827 return (IFState_service_add(ifstate, serviceID, config->method, 5828 config->method_data, 5829 NULL, NULL)); 5830} 5831 5832static void 5833interface_configuration_changed(interface_t * if_p, CFArrayRef all, 5834 boolean_t is_ipv4) 5835{ 5836 IFStateRef ifstate; 5837 ServiceConfigList scl; 5838 5839 /* if no services are defined, remove them all */ 5840 if (ServiceConfigListInit(&scl, is_ipv4, all, if_name(if_p)) == FALSE) { 5841 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, 5842 if_name(if_p), NULL); 5843 if (ifstate != NULL) { 5844 if (is_ipv4) { 5845 IFStateFreeIPv4Services(ifstate, FALSE); 5846 } 5847 else { 5848 IFStateFreeIPv6Services(ifstate, FALSE); 5849 } 5850 } 5851 return; 5852 } 5853 5854 /* stop services that are no longer active */ 5855 ServiceConfigListFreeInactiveServices(&scl, if_name(if_p)); 5856 5857 /* update services that are still defined */ 5858 ifstate = IFStateList_ifstate_create(&S_ifstate_list, if_p); 5859 if (ifstate != NULL) { 5860 int i; 5861 ServiceConfigRef config; 5862 5863 /* update each of the services that are configured */ 5864 for (i = 0, config = scl.list; i < scl.count; i++, config++) { 5865 (void)S_set_service(ifstate, config, scl.is_ipv4); 5866 } 5867 } 5868 ServiceConfigListFree(&scl); 5869 return; 5870} 5871 5872static void 5873handle_configuration_changed(SCDynamicStoreRef session, 5874 CFArrayRef all_ipv4, CFArrayRef all_ipv6) 5875{ 5876 int i; 5877 5878 for (i = 0; i < ifl_count(S_interfaces); i++) { 5879 interface_t * if_p = ifl_at_index(S_interfaces, i); 5880 5881 interface_configuration_changed(if_p, all_ipv4, IS_IPV4); 5882 interface_configuration_changed(if_p, all_ipv6, IS_IPV6); 5883 } 5884 return; 5885} 5886 5887static void 5888configuration_changed(SCDynamicStoreRef session) 5889{ 5890 CFArrayRef all_ipv4 = NULL; 5891 CFArrayRef all_ipv6 = NULL; 5892 5893 all_ipv4 = entity_all(session, &all_ipv6); 5894 handle_configuration_changed(session, all_ipv4, all_ipv6); 5895 my_CFRelease(&all_ipv4); 5896 my_CFRelease(&all_ipv6); 5897 return; 5898} 5899 5900static void 5901configure_from_cache(SCDynamicStoreRef session) 5902{ 5903 CFArrayRef all_ipv4 = NULL; 5904 CFArrayRef all_ipv6 = NULL; 5905 int count = 0; 5906 int i; 5907 5908 all_ipv4 = entity_all(session, &all_ipv6); 5909 if (all_ipv4 == NULL) { 5910 goto done; 5911 } 5912 5913 /* 5914 * Go through the list of interfaces and find those that have a 5915 * configuration. If an interface is present, pre-allocate an ifstate 5916 * entry so that the system startup will wait for that interface to 5917 * complete its initialization. 5918 */ 5919 for (i = 0; i < ifl_count(S_interfaces); i++) { 5920 CFDictionaryRef dict; 5921 interface_t * if_p = ifl_at_index(S_interfaces, i); 5922 CFStringRef ifn_cf = NULL; 5923 5924 ifn_cf = CFStringCreateWithCString(NULL, 5925 if_name(if_p), 5926 kCFStringEncodingASCII); 5927 if (ifn_cf == NULL) { 5928 continue; 5929 } 5930 dict = lookup_entity(all_ipv4, ifn_cf); 5931 if (dict != NULL) { 5932 (void)IFStateList_ifstate_create(&S_ifstate_list, if_p); 5933 count++; 5934 } 5935 CFRelease(ifn_cf); 5936 } 5937 5938 done: 5939 if (count == 0) { 5940 unblock_startup(session); 5941 } 5942 else { 5943 handle_configuration_changed(session, all_ipv4, all_ipv6); 5944 } 5945 my_CFRelease(&all_ipv4); 5946 my_CFRelease(&all_ipv6); 5947 5948 return; 5949} 5950 5951static void 5952notifier_init(SCDynamicStoreRef session) 5953{ 5954 CFMutableArrayRef keys = NULL; 5955 CFStringRef key; 5956 CFMutableStringRef pattern; 5957 CFMutableArrayRef patterns = NULL; 5958 CFRunLoopSourceRef rls; 5959 5960 if (session == NULL) { 5961 return; 5962 } 5963 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5964 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 5965 5966 /* notify when IPv4 config of any service changes */ 5967 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5968 kSCDynamicStoreDomainSetup, 5969 kSCCompAnyRegex, 5970 kSCEntNetIPv4); 5971 CFArrayAppendValue(patterns, key); 5972 CFRelease(key); 5973 /* notify when IPv6 config of any service changes */ 5974 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5975 kSCDynamicStoreDomainSetup, 5976 kSCCompAnyRegex, 5977 kSCEntNetIPv6); 5978 CFArrayAppendValue(patterns, key); 5979 CFRelease(key); 5980 /* notify when 6to4 config of any service changes */ 5981 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5982 kSCDynamicStoreDomainSetup, 5983 kSCCompAnyRegex, 5984 kSCEntNet6to4); 5985 CFArrayAppendValue(patterns, key); 5986 CFRelease(key); 5987 /* notify when IPv6 address changes on any interface */ 5988 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 5989 kSCDynamicStoreDomainState, 5990 kSCCompAnyRegex, 5991 kSCEntNetIPv6); 5992 CFArrayAppendValue(patterns, key); 5993 CFRelease(key); 5994 /* notify when Interface service <-> interface binding changes */ 5995 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 5996 kSCDynamicStoreDomainSetup, 5997 kSCCompAnyRegex, 5998 kSCEntNetInterface); 5999 CFArrayAppendValue(patterns, key); 6000 CFRelease(key); 6001 6002 /* notify when the link status of any interface changes */ 6003 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 6004 kSCDynamicStoreDomainState, 6005 kSCCompAnyRegex, 6006 kSCEntNetLink); 6007 CFArrayAppendValue(patterns, key); 6008 CFRelease(key); 6009 6010 /* notify when the bssid key of any interface changes */ 6011 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 6012 kSCDynamicStoreDomainState, 6013 kSCCompAnyRegex, 6014 kSCEntNetAirPort); 6015 CFArrayAppendValue(patterns, key); 6016 CFRelease(key); 6017 6018 /* notify for a refresh configuration request */ 6019 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 6020 kSCDynamicStoreDomainState, 6021 kSCCompAnyRegex, 6022 kSCEntNetRefreshConfiguration); 6023 CFArrayAppendValue(patterns, key); 6024 CFRelease(key); 6025 6026 /* notify when there's an ARP collision on any interface */ 6027 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 6028 kSCDynamicStoreDomainState, 6029 kSCCompAnyRegex, 6030 kSCEntNetIPv4ARPCollision); 6031 pattern = CFStringCreateMutableCopy(NULL, 0, key); 6032 CFStringAppend(pattern, CFSTR(".*")); 6033 CFRelease(key); 6034 CFArrayAppendValue(patterns, pattern); 6035 CFRelease(pattern); 6036 6037 /* notify when ActiveDuringSleepRequested changes */ 6038 key = ActiveDuringSleepRequestedKeyCopy(kSCCompAnyRegex); 6039 CFArrayAppendValue(patterns, key); 6040 CFRelease(key); 6041 6042 /* notify when list of interfaces changes */ 6043 key = SCDynamicStoreKeyCreateNetworkInterface(NULL, 6044 kSCDynamicStoreDomainState); 6045 CFArrayAppendValue(keys, key); 6046 CFRelease(key); 6047 6048 /* notify when the service order changes */ 6049 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 6050 kSCDynamicStoreDomainSetup, 6051 kSCEntNetIPv4); 6052 CFArrayAppendValue(keys, key); 6053 CFRelease(key); 6054 6055 /* notify when ComputerName/LocalHostName changes */ 6056 S_computer_name_key = SCDynamicStoreKeyCreateComputerName(NULL); 6057 CFArrayAppendValue(keys, S_computer_name_key); 6058 S_hostnames_key = SCDynamicStoreKeyCreateHostNames(NULL); 6059 CFArrayAppendValue(keys, S_hostnames_key); 6060 6061 SCDynamicStoreSetNotificationKeys(session, keys, patterns); 6062 CFRelease(keys); 6063 CFRelease(patterns); 6064 6065 rls = SCDynamicStoreCreateRunLoopSource(NULL, session, 0); 6066 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 6067 CFRelease(rls); 6068 6069 /* initialize the computer name */ 6070 computer_name_update(session); 6071 return; 6072} 6073 6074static boolean_t 6075update_interface_list() 6076{ 6077 interface_list_t * new_interfaces = NULL; 6078 6079 new_interfaces = ifl_init(); 6080 if (new_interfaces == NULL) { 6081 my_log(LOG_ERR, "IPConfiguration: ifl_init failed"); 6082 return (FALSE); 6083 } 6084 if (S_interfaces) { 6085 ifl_free(&S_interfaces); 6086 } 6087 S_interfaces = new_interfaces; 6088 6089 return (TRUE); 6090} 6091 6092interface_list_t * 6093get_interface_list(void) 6094{ 6095 if (S_interfaces == NULL) { 6096 S_interfaces = ifl_init(); 6097 } 6098 return (S_interfaces); 6099} 6100 6101 6102/* 6103 * Function: check_for_detached_interfaces 6104 * Purpose: 6105 * Remove interface state for any interface that has been removed. 6106 * Create a temporary list to store the name of each interface that 6107 * has been removed. Iterate through that list to remove individual 6108 * interface state records. This is done to avoid problems with 6109 * iterating over a list while it is modified. 6110 */ 6111static void 6112check_for_detached_interfaces() 6113{ 6114 int count = dynarray_count(&S_ifstate_list); 6115 const char * * names = NULL; 6116 int names_count = 0; 6117 int i; 6118 6119 6120 if (count == 0) { 6121 return; 6122 } 6123 6124 /* allocate worst case scenario in which each ifstate needs to be removed */ 6125 names = (const char * *)malloc(sizeof(char *) * count); 6126 if (names == NULL) { 6127 return; 6128 } 6129 for (i = 0; i < count; i++) { 6130 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 6131 6132 if (ifl_find_name(S_interfaces, if_name(ifstate->if_p)) == NULL) { 6133 names[names_count++] = if_name(ifstate->if_p); 6134 } 6135 } 6136 for (i = 0; i < names_count; i++) { 6137 IFStateList_ifstate_free(&S_ifstate_list, names[i]); 6138 } 6139 free(names); 6140 return; 6141} 6142 6143static void 6144runloop_observer(CFRunLoopObserverRef observer, 6145 CFRunLoopActivity activity, void *info) 6146{ 6147 if (S_scd_session == NULL) { 6148 return; 6149 } 6150 if (S_linklocal_needs_attention) { 6151 CFArrayRef service_order = NULL; 6152 6153 S_linklocal_needs_attention = FALSE; 6154 service_order = S_get_service_order(S_scd_session); 6155 my_log(LOG_DEBUG, "runloop_observer: calling S_linklocal_elect"); 6156 S_linklocal_elect(service_order); 6157 my_CFRelease(&service_order); 6158 } 6159 if (S_active_during_sleep_needs_attention) { 6160 S_active_during_sleep_needs_attention = FALSE; 6161 ActiveDuringSleepProcess(&S_ifstate_list); 6162 } 6163 my_SCDynamicStorePublish(S_scd_session); 6164 return; 6165} 6166 6167/* 6168 * Function: woke_from_hibernation 6169 * 6170 * Purpose: 6171 * When we wake from sleep, check whether we woke from a hibernation 6172 * image or a regular wake from sleep. 6173 */ 6174 6175#define IO_PATH_PM_ROOT_DOMAIN kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain" 6176STATIC boolean_t 6177woke_from_hibernation(void) 6178{ 6179 CFDataRef hib_prop; 6180 uint32_t hibernate_state; 6181 6182 hibernate_state = kIOHibernateStateInactive; 6183 hib_prop = myIORegistryEntryCopyProperty(IO_PATH_PM_ROOT_DOMAIN, 6184 CFSTR(kIOHibernateStateKey)); 6185 if (isA_CFData(hib_prop) != NULL 6186 && CFDataGetLength(hib_prop) == sizeof(hibernate_state)) { 6187 hibernate_state = *((uint32_t *)(void *)CFDataGetBytePtr(hib_prop)); 6188 } 6189 my_CFRelease(&hib_prop); 6190 return (hibernate_state == kIOHibernateStateWakingFromHibernate); 6191} 6192 6193STATIC void 6194S_ifstate_process_wake(IFStateRef ifstate) 6195{ 6196 wake_data_t event_data; 6197 interface_t * if_p = ifstate->if_p; 6198 link_status_t link_status; 6199 6200 link_status = if_get_link_status(if_p); 6201 event_data.flags = 0; 6202 if (S_woke_from_hibernation) { 6203 event_data.flags |= kWakeFlagsFromHibernation; 6204 } 6205 else if (link_status.valid 6206 && link_status.active == FALSE 6207 && link_status.wake_on_same_network) { 6208 my_log(LOG_DEBUG, "%s: wake on same network (link inactive)", 6209 if_name(if_p)); 6210 return; 6211 } 6212 if (ifstate->link_timer_suppressed) { 6213 ifstate->link_timer_suppressed = FALSE; 6214 my_log(LOG_DEBUG, "%s: processing link timer expired at wake", 6215 if_name(if_p)); 6216 process_link_timer_expired(ifstate); 6217 } 6218 ifstate->wake_generation = S_wake_generation; 6219 my_log(LOG_DEBUG, "%s: Wake", if_name(if_p)); 6220 if (if_is_wireless(if_p)) { 6221 CFStringRef ssid; 6222 struct ether_addr bssid; 6223 6224 ssid = S_copy_ssid_bssid(ifstate->ifname, &bssid); 6225 if (ssid != NULL 6226 && ifstate->ssid != NULL) { 6227 if (!CFEqual(ssid, ifstate->ssid)) { 6228 event_data.flags |= kWakeFlagsSSIDChanged; 6229 } 6230 else if (bcmp(&bssid, &ifstate->bssid, sizeof(bssid))) { 6231 event_data.flags |= kWakeFlagsBSSIDChanged; 6232 } 6233 IFState_set_ssid_bssid(ifstate, ssid, &bssid); 6234 } 6235 my_CFRelease(&ssid); 6236 } 6237 if (dynarray_count(&ifstate->services) > 0) { 6238 /* attach IPv4 in case the interface went away during sleep */ 6239 inet_attach_interface(if_name(if_p)); 6240 service_list_event(&ifstate->services, IFEventID_wake_e, 6241 (void *)&event_data); 6242 } 6243 if (dynarray_count(&ifstate->services_v6) > 0) { 6244 /* attach IPv6 in case the interface went away during sleep */ 6245 inet6_attach_interface(if_name(if_p)); 6246 6247 /* make sure IPv6 link-local is started */ 6248 if (link_status.valid == FALSE 6249 || link_status.active) { 6250 (void)inet6_linklocal_start(if_name(if_p), !if_is_awdl(if_p)); 6251 } 6252 /* update our neighbor advert list */ 6253 if (ifstate->neighbor_advert_list != NULL) { 6254 CFRelease(ifstate->neighbor_advert_list); 6255 } 6256 ifstate->neighbor_advert_list 6257 = S_copy_neighbor_advert_list(S_scd_session, ifstate->ifname); 6258 service_list_event(&ifstate->services_v6, IFEventID_wake_e, 6259 (void *)&event_data); 6260 } 6261 return; 6262} 6263 6264STATIC void 6265S_deliver_wake_event(void) 6266{ 6267 int i; 6268 int if_count = dynarray_count(&S_ifstate_list); 6269 6270 for (i = 0; i < if_count; i++) { 6271 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 6272 6273 if (ifstate->wake_generation == S_wake_generation) { 6274 /* we've already seen this wake via link status event */ 6275 my_log(LOG_DEBUG, "%s: ignoring wake (already processed)", 6276 if_name(ifstate->if_p)); 6277 continue; 6278 } 6279 S_ifstate_process_wake(ifstate); 6280 } 6281 return; 6282} 6283 6284static void 6285power_changed(void * refcon, io_service_t service, natural_t msg_type, 6286 void * msg) 6287{ 6288 boolean_t ack_msg = TRUE; 6289 6290 switch (msg_type) { 6291 case kIOMessageSystemWillPowerOff: 6292 case kIOMessageSystemWillRestart: 6293 /* 6294 * Note: we never see these messages because we get killed 6295 * off before that would happen (SIGTERM, SIGKILL). 6296 */ 6297 break; 6298 6299 case kIOMessageSystemWillNotSleep: 6300 case kIOMessageSystemWillNotPowerOff: 6301 ack_msg = FALSE; 6302 break; 6303 6304 case kIOMessageSystemWillSleep: 6305 /* sleep */ 6306 if (S_awake == FALSE) { 6307 /* already asleep (should not happen) */ 6308 break; 6309 } 6310 my_log(LOG_DEBUG, "IPConfiguration: Sleep"); 6311 S_awake = FALSE; 6312 IFStateList_all_services_sleep(&S_ifstate_list); 6313 break; 6314 6315 case kIOMessageSystemWillPowerOn: 6316 if (S_awake) { 6317 /* already awake (should not happen) */ 6318 break; 6319 } 6320 my_log(LOG_DEBUG, "IPConfiguration: Wake"); 6321 S_awake = TRUE; 6322 S_wake_time = timer_current_secs(); 6323 S_wake_generation++; 6324 S_woke_from_hibernation = woke_from_hibernation(); 6325 S_deliver_wake_event(); 6326 break; 6327 case kIOMessageSystemHasPoweredOn: 6328 /* wake */ 6329 ack_msg = FALSE; 6330 break; 6331 6332 default: 6333 break; 6334 } 6335 if (ack_msg) { 6336 IOAllowPowerChange(S_power_connection, (long)msg); 6337 } 6338 return; 6339} 6340 6341 6342static io_connect_t 6343power_notification_init() 6344{ 6345 io_object_t obj; 6346 CFRunLoopSourceRef rls; 6347 IONotificationPortRef port; 6348 io_connect_t power_connection; 6349 6350 power_connection = IORegisterForSystemPower(NULL, &port, 6351 power_changed, &obj); 6352 if (power_connection != 0) { 6353 rls = IONotificationPortGetRunLoopSource(port); 6354 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 6355 } 6356 return (power_connection); 6357} 6358 6359#if ! TARGET_OS_EMBEDDED 6360#define POWER_INTEREST (kIOPMEarlyWakeNotification \ 6361 | kIOPMCapabilityNetwork \ 6362 | kIOPMCapabilityCPU) 6363 6364void 6365new_power_changed(void * param, 6366 IOPMConnection connection, 6367 IOPMConnectionMessageToken token, 6368 IOPMSystemPowerStateCapabilities capabilities) 6369{ 6370 IOReturn ret; 6371 6372 if ((capabilities & kIOPMCapabilityCPU) != 0) { 6373 if (S_awake == FALSE) { 6374 S_woke_from_hibernation = woke_from_hibernation(); 6375 S_wake_generation++; 6376 S_wake_time = timer_current_secs(); 6377 } 6378 S_awake = TRUE; 6379 if ((capabilities & kIOPMEarlyWakeNotification) != 0) { 6380 my_log(LOG_DEBUG, "IPConfiguration: Early Wake"); 6381 } 6382 else if (S_wake_event_sent == FALSE) { 6383 my_log(LOG_DEBUG, "IPConfiguration: Wake"); 6384 S_deliver_wake_event(); 6385 S_wake_event_sent = TRUE; 6386 } 6387 } 6388 else { 6389 /* sleep */ 6390 S_awake = FALSE; 6391 S_wake_event_sent = FALSE; 6392 my_log(LOG_DEBUG, "IPConfiguration: Sleep"); 6393 IFStateList_all_services_sleep(&S_ifstate_list); 6394 6395 } 6396 ret = IOPMConnectionAcknowledgeEvent(connection, token); 6397 if (ret != kIOReturnSuccess) { 6398 my_log(LOG_NOTICE, "IPConfiguration: " 6399 "IOPMConnectionAcknowledgeEvent failed, 0x%08x", ret); 6400 } 6401 return; 6402} 6403 6404static void 6405new_power_notification_init(void) 6406{ 6407 IOPMConnection connection = NULL; 6408 IOReturn ret; 6409 6410 ret = IOPMConnectionCreate(CFSTR("IPConfiguration"), 6411 POWER_INTEREST, 6412 &connection); 6413 if (ret != kIOReturnSuccess) { 6414 my_log(LOG_ERR, 6415 "IPConfiguration: IOPMConnectionCreate failed, 0x%08x", ret); 6416 goto failed; 6417 } 6418 ret = IOPMConnectionSetNotification(connection, NULL, 6419 new_power_changed); 6420 6421 if (ret != kIOReturnSuccess) { 6422 my_log(LOG_ERR, "IPConfiguration:" 6423 "IOPMConnectionSetNotification failed, 0x%08x", ret); 6424 goto failed; 6425 } 6426 6427 ret = IOPMConnectionScheduleWithRunLoop(connection, 6428 CFRunLoopGetCurrent(), 6429 kCFRunLoopDefaultMode); 6430 if (ret != kIOReturnSuccess) { 6431 my_log(LOG_ERR, "IPConfiguration:" 6432 "IOPMConnectionScheduleWithRunloop failed, 0x%08x", ret); 6433 goto failed; 6434 } 6435 return; 6436 6437 failed: 6438 if (connection != NULL) { 6439 IOPMConnectionRelease(connection); 6440 } 6441 return; 6442} 6443 6444#endif /* ! TARGET_OS_EMBEDDED */ 6445 6446static boolean_t 6447start_initialization(SCDynamicStoreRef session) 6448{ 6449 S_observer = CFRunLoopObserverCreate(NULL, 6450 kCFRunLoopAllActivities, 6451 TRUE, 0, runloop_observer, NULL); 6452 if (S_observer != NULL) { 6453 CFRunLoopAddObserver(CFRunLoopGetCurrent(), S_observer, 6454 kCFRunLoopDefaultMode); 6455 } 6456 else { 6457 my_log(LOG_NOTICE, 6458 "start_initialization: CFRunLoopObserverCreate failed!"); 6459 } 6460 S_setup_service_prefix = SCDynamicStoreKeyCreate(NULL, 6461 CFSTR("%@/%@/%@/"), 6462 kSCDynamicStoreDomainSetup, 6463 kSCCompNetwork, 6464 kSCCompService); 6465 6466 S_state_interface_prefix = SCDynamicStoreKeyCreate(NULL, 6467 CFSTR("%@/%@/%@/"), 6468 kSCDynamicStoreDomainState, 6469 kSCCompNetwork, 6470 kSCCompInterface); 6471 6472 /* install run-time notifiers */ 6473 notifier_init(session); 6474 6475 (void)update_interface_list(); 6476 6477 (void)S_netboot_init(); 6478 6479 configure_from_cache(session); 6480 6481 /* register for sleep/wake */ 6482#if ! TARGET_OS_EMBEDDED 6483 if (S_use_maintenance_wake) { 6484 new_power_notification_init(); 6485 } 6486 else { 6487 S_power_connection = power_notification_init(); 6488 } 6489#else /* ! TARGET_OS_EMBEDDED */ 6490 S_power_connection = power_notification_init(); 6491#endif /* ! TARGET_OS_EMBEDDED */ 6492 return (TRUE); 6493} 6494 6495static void 6496link_refresh(SCDynamicStoreRef session, CFStringRef cache_key) 6497{ 6498 CFStringRef ifn_cf = NULL; 6499 IFStateRef ifstate; 6500 int j; 6501 6502 if (CFStringHasPrefix(cache_key, S_state_interface_prefix) == FALSE) { 6503 return; 6504 } 6505 /* State:/Network/Interface/<ifname>/RefreshConfiguration */ 6506 ifn_cf = my_CFStringCopyComponent(cache_key, CFSTR("/"), 3); 6507 if (ifn_cf == NULL) { 6508 return; 6509 } 6510 ifstate = IFStateListGetIFState(&S_ifstate_list, ifn_cf, NULL); 6511 if (ifstate == NULL || ifstate->netboot) { 6512 /* don't propagate media status events for netboot interface */ 6513 goto done; 6514 } 6515 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 6516 ServiceRef service_p = dynarray_element(&ifstate->services, j); 6517 6518 config_method_renew(service_p); 6519 } 6520 service_list_event(&ifstate->services_v6, IFEventID_renew_e, NULL); 6521 6522 done: 6523 my_CFRelease(&ifn_cf); 6524 return; 6525} 6526 6527static void 6528ipv6_interface_address_changed(SCDynamicStoreRef session, 6529 CFStringRef cache_key) 6530{ 6531 inet6_addrlist_t addr_list; 6532 CFStringRef ifn_cf; 6533 IFStateRef ifstate; 6534 6535 if (CFStringHasPrefix(cache_key, S_state_interface_prefix) == FALSE) { 6536 return; 6537 } 6538 6539 /* figure out which interface this belongs to and deliver the event */ 6540 6541 /* State:/Network/Interface/<ifname>/IPv6 */ 6542 ifn_cf = my_CFStringCopyComponent(cache_key, CFSTR("/"), 3); 6543 if (ifn_cf == NULL) { 6544 return; 6545 } 6546 ifstate = IFStateListGetIFState(&S_ifstate_list, ifn_cf, NULL); 6547 if (ifstate == NULL) { 6548 /* not tracking this event */ 6549 goto done; 6550 } 6551 /* get the addresses from the interface and deliver the event */ 6552 inet6_addrlist_copy(&addr_list, if_link_index(ifstate->if_p)); 6553 if (G_IPConfiguration_verbose) { 6554 CFStringRef str; 6555 6556 str = inet6_addrlist_copy_description(&addr_list); 6557 my_log(~LOG_DEBUG, "%@: IPv6 address list = %@", ifn_cf, str); 6558 CFRelease(str); 6559 } 6560 service_list_event(&ifstate->services_v6, 6561 IFEventID_ipv6_address_changed_e, &addr_list); 6562 6563 /* send neighbor advertisements if necessary */ 6564 S_process_neighbor_adverts(ifstate, &addr_list); 6565 6566 inet6_addrlist_free(&addr_list); 6567 6568 done: 6569 my_CFRelease(&ifn_cf); 6570 return; 6571} 6572 6573 6574#include "my_darwin.h" 6575 6576#ifndef NO_WIRELESS 6577 6578#include <Apple80211/Apple80211API.h> 6579#include <Kernel/IOKit/apple80211/apple80211_ioctl.h> 6580 6581static CFStringRef 6582S_copy_ssid_bssid(CFStringRef ifname, struct ether_addr * ap_mac) 6583{ 6584 Apple80211Err error; 6585 CFMutableDataRef ssid; 6586 CFStringRef ssid_str = NULL; 6587 Apple80211Ref wref; 6588 6589 error = Apple80211Open(&wref); 6590 if (error != kA11NoErr) { 6591 my_log(LOG_DEBUG, "Apple80211Open failed, 0x%x"); 6592 return (NULL); 6593 } 6594 error = Apple80211BindToInterface(wref, ifname); 6595 if (error != kA11NoErr) { 6596 goto done; 6597 } 6598 ssid = CFDataCreateMutable(kCFAllocatorDefault, 0); 6599 if (Apple80211Get((Apple80211Ref)wref, APPLE80211_IOC_SSID, 0, 6600 ssid, 0) == kA11NoErr) { 6601 ssid_str = CFStringCreateWithBytes(NULL, 6602 CFDataGetBytePtr(ssid), 6603 CFDataGetLength(ssid), 6604 kCFStringEncodingUTF8, 6605 FALSE); 6606 if (ssid_str == NULL) { 6607 ssid_str = CFStringCreateWithBytes(NULL, 6608 CFDataGetBytePtr(ssid), 6609 CFDataGetLength(ssid), 6610 kCFStringEncodingMacRoman, 6611 FALSE); 6612 } 6613 } 6614 CFRelease(ssid); 6615 if (ap_mac != NULL) { 6616 (void)Apple80211Get((Apple80211Ref)wref, APPLE80211_IOC_BSSID, 0, 6617 ap_mac, sizeof(*ap_mac)); 6618 } 6619 6620 done: 6621 Apple80211Close(wref); 6622 return (ssid_str); 6623} 6624 6625#else /* NO_WIRELESS */ 6626 6627static CFStringRef 6628S_copy_ssid_bssid(CFStringRef ifname, struct ether_addr * ap_mac) 6629{ 6630 return (NULL); 6631} 6632 6633#endif /* NO_WIRELESS */ 6634 6635STATIC void 6636process_link_timer_expired(IFStateRef ifstate) 6637{ 6638 my_log(LOG_DEBUG, "%s: link inactive timer fired", 6639 if_name(ifstate->if_p)); 6640 service_list_event(&ifstate->services, 6641 IFEventID_link_timer_expired_e, NULL); 6642 service_list_event(&ifstate->services_v6, 6643 IFEventID_link_timer_expired_e, NULL); 6644 if (dynarray_count(&ifstate->services_v6) != 0) { 6645 (void)inet6_linklocal_stop(if_name(ifstate->if_p)); 6646 } 6647 return; 6648} 6649 6650static void 6651link_timer_expired(void * arg0, void * arg1, void * arg2) 6652{ 6653 process_link_timer_expired(arg0); 6654 return; 6655} 6656 6657static void 6658ap_key_changed(SCDynamicStoreRef session, CFStringRef cache_key) 6659{ 6660 struct ether_addr bssid; 6661 interface_t * if_p; 6662 CFStringRef ifn_cf; 6663 IFStateRef ifstate; 6664 link_status_t link; 6665 uint32_t j; 6666 CFStringRef ssid; 6667 boolean_t wireless_did_roam; 6668 6669 if (CFStringHasPrefix(cache_key, S_state_interface_prefix) == FALSE) { 6670 return; 6671 } 6672 6673 /* State:/Network/Interface/<ifname>/Airport */ 6674 ifn_cf = my_CFStringCopyComponent(cache_key, CFSTR("/"), 3); 6675 if (ifn_cf == NULL) { 6676 return; 6677 } 6678 ifstate = IFStateListGetIFState(&S_ifstate_list, ifn_cf, NULL); 6679 my_CFRelease(&ifn_cf); 6680 if (ifstate == NULL || ifstate->netboot) { 6681 /* don't propagate media status events for netboot interface */ 6682 goto done; 6683 } 6684 if_p = ifl_find_name(S_interfaces, if_name(ifstate->if_p)); 6685 if (if_p == NULL) { 6686 /* interface doesn't exist */ 6687 goto done; 6688 } 6689 link = if_link_status_update(if_p); 6690 if (if_is_wireless(ifstate->if_p) == FALSE) { 6691 goto done; 6692 } 6693 if ((link.valid && !link.active) 6694 || (ifstate->if_p->link_status.valid 6695 && !ifstate->if_p->link_status.active)) { 6696 /* 6697 * Link is/was down, no need to handle it now. This will be handled 6698 * when the next link up event comes in. 6699 */ 6700 goto done; 6701 } 6702 ssid = S_copy_ssid_bssid(ifstate->ifname, &bssid); 6703 if (G_IPConfiguration_verbose) { 6704 if (ssid != NULL) { 6705 my_log(LOG_DEBUG, "%s: SSID %@ BSSID %s", 6706 if_name(if_p), ssid, ether_ntoa(&bssid)); 6707 } 6708 else { 6709 my_log(LOG_DEBUG, "%s: no SSID", if_name(if_p)); 6710 } 6711 } 6712 6713 /* check whether just the bssid has changed i.e. we roamed */ 6714 wireless_did_roam = IFState_wireless_did_roam(ifstate, ssid, &bssid); 6715 my_CFRelease(&ssid); 6716 if (!wireless_did_roam) { 6717 goto done; 6718 } 6719 6720 /* update just the BSSID */ 6721 IFState_set_bssid(ifstate, &bssid); 6722 6723 /* Notify v4 services */ 6724 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 6725 ServiceRef service_p = dynarray_element(&ifstate->services, j); 6726 6727 config_method_bssid_changed(service_p); 6728 } 6729 6730 /* Notify v6 services */ 6731 service_list_event(&ifstate->services_v6, IFEventID_bssid_changed_e, 6732 NULL); 6733 6734 done: 6735 return; 6736} 6737 6738static void 6739link_key_changed(SCDynamicStoreRef session, CFStringRef cache_key) 6740{ 6741 CFDictionaryRef dict = NULL; 6742 interface_t * if_p; 6743 CFStringRef ifn_cf; 6744 char ifn[IFNAMSIZ + 1]; 6745 IFStateRef ifstate; 6746 int j; 6747 link_status_t link_status; 6748 boolean_t link_address_changed = FALSE; 6749 void * network_changed = NULL; 6750 6751 if (CFStringHasPrefix(cache_key, S_state_interface_prefix) == FALSE) { 6752 return; 6753 } 6754 /* State:/Network/Interface/<ifname>/Link */ 6755 ifn_cf = my_CFStringCopyComponent(cache_key, CFSTR("/"), 3); 6756 if (ifn_cf == NULL) { 6757 return; 6758 } 6759 my_CFStringToCStringAndLength(ifn_cf, ifn, sizeof(ifn)); 6760 my_CFRelease(&ifn_cf); 6761 ifstate = IFStateList_ifstate_with_name(&S_ifstate_list, ifn, NULL); 6762 dict = my_SCDynamicStoreCopyDictionary(session, cache_key); 6763 if (dict != NULL) { 6764 if (CFDictionaryContainsKey(dict, kSCPropNetLinkDetaching)) { 6765 if (ifstate != NULL) { 6766 IFStateFreeIPv4Services(ifstate, TRUE); 6767 IFStateFreeIPv6Services(ifstate, TRUE); 6768 } 6769 goto done; 6770 } 6771 } 6772 if_p = ifl_find_name(S_interfaces, ifn); 6773 if (if_p == NULL) { 6774 /* interface doesn't exist */ 6775 goto done; 6776 } 6777 link_status = if_link_status_update(if_p); 6778 if (link_status.valid) { 6779 /* make sure address information is up to date */ 6780 link_address_changed = if_link_update(if_p); 6781 } 6782 if (ifstate == NULL || ifstate->netboot) { 6783 /* don't propagate media status events for netboot interface */ 6784 goto done; 6785 } 6786 if_link_copy(ifstate->if_p, if_p); 6787 if (G_IPConfiguration_verbose) { 6788 if (link_status.valid == FALSE) { 6789 my_log(LOG_DEBUG, "%s link is unknown", ifn); 6790 } 6791 else { 6792 my_log(LOG_DEBUG, "%s link %s%s%s", 6793 ifn, link_status.active ? "ACTIVE" : "INACTIVE", 6794 link_address_changed ? " [link address changed]" : "", 6795 link_status.wake_on_same_network 6796 ? " [wake on same network]" : ""); 6797 } 6798 } 6799 if (link_address_changed == FALSE 6800 && S_wake_generation != ifstate->wake_generation) { 6801 my_log(LOG_DEBUG, 6802 "%s: link status changed at wake", ifn); 6803 S_ifstate_process_wake(ifstate); 6804 if (link_status.wake_on_same_network) { 6805 goto done; 6806 } 6807 } 6808 if (if_is_wireless(ifstate->if_p)) { 6809 struct ether_addr bssid; 6810 CFStringRef ssid; 6811 6812 ssid = S_copy_ssid_bssid(ifstate->ifname, &bssid); 6813 if (G_IPConfiguration_verbose) { 6814 if (ssid != NULL) { 6815 my_log(LOG_DEBUG, "%s: SSID %@ BSSID %s", 6816 ifn, ssid, ether_ntoa(&bssid)); 6817 } 6818 else { 6819 my_log(LOG_DEBUG, "%s: no SSID", ifn); 6820 } 6821 } 6822 if (ssid != NULL) { 6823 if (ifstate->ssid != NULL 6824 && !CFEqual(ssid, ifstate->ssid)) { 6825 network_changed = (void *)1; 6826 } 6827 /* remember the last ssid */ 6828 IFState_set_ssid_bssid(ifstate, ssid, &bssid); 6829 CFRelease(ssid); 6830 } 6831 } 6832 if (link_status.valid && link_status.active == FALSE) { 6833 if (S_awake == FALSE) { 6834 if (G_IPConfiguration_verbose) { 6835 my_log(LOG_DEBUG, 6836 "%s: suppressing link inactive timer (going to sleep)", 6837 ifn); 6838 } 6839 timer_cancel(ifstate->timer); 6840 ifstate->link_timer_suppressed = TRUE; 6841 } 6842 else { 6843 ifstate->link_timer_suppressed = FALSE; 6844 if (G_IPConfiguration_verbose) { 6845 my_log(LOG_DEBUG, 6846 "%s: scheduling link inactive timer for %d.%06d secs", 6847 ifn, 6848 S_link_inactive_secs.tv_sec, 6849 S_link_inactive_secs.tv_usec); 6850 } 6851 timer_set_relative(ifstate->timer, 6852 S_link_inactive_secs, link_timer_expired, 6853 ifstate, NULL, NULL); 6854 } 6855 } 6856 else { 6857 ifstate->link_timer_suppressed = FALSE; 6858 timer_cancel(ifstate->timer); 6859 } 6860 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 6861 ServiceRef service_p = dynarray_element(&ifstate->services, j); 6862 6863 config_method_media(service_p, network_changed); 6864 } 6865 if (if_ift_type(ifstate->if_p) != IFT_STF) { 6866 if (link_address_changed) { 6867 /* first stop IPv6 link-local */ 6868 my_log(LOG_DEBUG, "%s: link address changed", if_name(if_p)); 6869 (void)inet6_linklocal_stop(if_name(if_p)); 6870 } 6871 if ((link_status.valid == FALSE || link_status.active) 6872 && dynarray_count(&ifstate->services_v6) != 0) { 6873 /* start IPv6 link-local */ 6874 (void)inet6_linklocal_start(if_name(if_p), !if_is_awdl(if_p)); 6875 } 6876 } 6877 service_list_event(&ifstate->services_v6, IFEventID_link_status_changed_e, 6878 (void *)network_changed); 6879 done: 6880 my_CFRelease(&dict); 6881 return; 6882} 6883 6884static void 6885arp_collision(SCDynamicStoreRef session, CFStringRef cache_key) 6886{ 6887 arp_collision_data_t evdata; 6888 void * hwaddr = NULL; 6889 int hwlen; 6890 CFStringRef ifn_cf = NULL; 6891 struct in_addr ip_addr; 6892 IFStateRef ifstate; 6893 6894 ifn_cf = IPv4ARPCollisionKeyParse(cache_key, &ip_addr, &hwaddr, &hwlen); 6895 if (ifn_cf == NULL || hwaddr == NULL) { 6896 goto done; 6897 } 6898 ifstate = IFStateListGetIFState(&S_ifstate_list, ifn_cf, NULL); 6899 if (ifstate == NULL || ifstate->netboot) { 6900 /* don't propogate collision events for netboot interface */ 6901 goto done; 6902 } 6903 if (S_is_our_hardware_address(NULL, if_link_arptype(ifstate->if_p), 6904 hwaddr, hwlen)) { 6905 goto done; 6906 } 6907 evdata.ip_addr = ip_addr; 6908 evdata.hwaddr = hwaddr; 6909 evdata.hwlen = hwlen; 6910 evdata.is_sleep_proxy 6911 = S_is_sleep_proxy_hardware_address(session, ifstate, hwaddr, hwlen); 6912 service_list_event(&ifstate->services, IFEventID_arp_collision_e, &evdata); 6913 6914 done: 6915 if (hwaddr != NULL) { 6916 free(hwaddr); 6917 } 6918 my_CFRelease(&ifn_cf); 6919 return; 6920} 6921 6922static void 6923dhcp_preferences_changed(SCPreferencesRef prefs, 6924 SCPreferencesNotification type, 6925 void * info) 6926{ 6927 int i; 6928 6929 if ((type & kSCPreferencesNotificationApply) == 0) { 6930 return; 6931 } 6932 6933 /* merge in the new requested parameters */ 6934 S_add_dhcp_parameters(prefs); 6935 SCPreferencesSynchronize(prefs); 6936 6937 for (i = 0; i < dynarray_count(&S_ifstate_list); i++) { 6938 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 6939 int j; 6940 6941 /* ask each service to renew immediately to pick up new options */ 6942 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 6943 ServiceRef service_p = dynarray_element(&ifstate->services, j); 6944 6945 config_method_renew(service_p); 6946 } 6947 } 6948 return; 6949} 6950 6951static void 6952handle_change(SCDynamicStoreRef session, CFArrayRef changes, void * arg) 6953{ 6954 boolean_t config_changed = FALSE; 6955 CFIndex count; 6956 CFIndex i; 6957 boolean_t iflist_changed = FALSE; 6958 boolean_t name_changed = FALSE; 6959 boolean_t order_changed = FALSE; 6960 CFStringRef setup_global_ipv4_key = NULL; 6961 CFMutableArrayRef state_changes = NULL; 6962 6963 count = CFArrayGetCount(changes); 6964 if (count == 0) { 6965 goto done; 6966 } 6967 if (G_IPConfiguration_verbose) { 6968 my_log(LOG_DEBUG, "Changes: %@ (%d)", changes, count); 6969 } 6970 for (i = 0; i < count; i++) { 6971 CFStringRef cache_key = CFArrayGetValueAtIndex(changes, i); 6972 6973 if (CFEqual(cache_key, S_computer_name_key) 6974 || CFEqual(cache_key, S_hostnames_key)) { 6975 name_changed = TRUE; 6976 } 6977 else if (CFStringHasPrefix(cache_key, kSCDynamicStoreDomainSetup)) { 6978 if (setup_global_ipv4_key == NULL) { 6979 setup_global_ipv4_key 6980 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 6981 kSCDynamicStoreDomainSetup, 6982 kSCEntNetIPv4); 6983 } 6984 if (CFEqual(cache_key, setup_global_ipv4_key)) { 6985 /* service order may have changed */ 6986 order_changed = TRUE; 6987 } 6988 /* IPv4 configuration changed */ 6989 config_changed = TRUE; 6990 } 6991 else if (CFStringHasSuffix(cache_key, kSCCompInterface)) { 6992 /* list of interfaces changed */ 6993 iflist_changed = TRUE; 6994 } 6995 else { 6996 if (state_changes == NULL) { 6997 state_changes 6998 = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 6999 } 7000 CFArrayAppendValue(state_changes, cache_key); 7001 } 7002 } 7003 /* the computer name changed */ 7004 if (name_changed) { 7005 computer_name_update(session); 7006 } 7007 /* an interface was added/removed */ 7008 if (iflist_changed) { 7009 if (update_interface_list()) { 7010 config_changed = TRUE; 7011 check_for_detached_interfaces(); 7012 } 7013 } 7014 /* configuration changed */ 7015 if (config_changed) { 7016 configuration_changed(session); 7017 } 7018 /* look through remaining State: key changes */ 7019 if (state_changes != NULL) { 7020 count = CFArrayGetCount(state_changes); 7021 } 7022 else { 7023 count = 0; 7024 } 7025 for (i = 0; i < count; i++) { 7026 CFStringRef cache_key = CFArrayGetValueAtIndex(state_changes, i); 7027 7028 if (CFStringHasSuffix(cache_key, kSCEntNetLink)) { 7029 link_key_changed(session, cache_key); 7030 } 7031 else if (CFStringHasSuffix(cache_key, kSCEntNetAirPort)) { 7032 ap_key_changed(session, cache_key); 7033 } 7034 else if (CFStringHasSuffix(cache_key, kSCEntNetRefreshConfiguration)) { 7035 link_refresh(session, cache_key); 7036 } 7037 else if (CFStringHasSuffix(cache_key, kSCEntNetIPv6)) { 7038 ipv6_interface_address_changed(session, cache_key); 7039 } 7040 else if (CFStringHasSuffix(cache_key, 7041 kSCEntNetInterfaceActiveDuringSleepRequested)) { 7042 ActiveDuringSleepRequestedKeyChanged(session, cache_key); 7043 } 7044 7045 else { 7046 CFRange range = CFRangeMake(0, CFStringGetLength(cache_key)); 7047 7048 if (CFStringFindWithOptions(cache_key, kSCEntNetIPv4ARPCollision, 7049 range, 0, NULL)) { 7050 arp_collision(session, cache_key); 7051 } 7052 } 7053 } 7054 7055 /* service order may have changed */ 7056 if (order_changed) { 7057 linklocal_set_needs_attention(); 7058 } 7059 7060 done: 7061 my_CFRelease(&setup_global_ipv4_key); 7062 my_CFRelease(&state_changes); 7063 return; 7064} 7065 7066#if ! TARGET_OS_EMBEDDED 7067 7068static void 7069user_confirm(CFUserNotificationRef userNotification, 7070 CFOptionFlags response_flags) 7071{ 7072 int i; 7073 7074 /* clean-up the notification */ 7075 for (i = 0; i < dynarray_count(&S_ifstate_list); i++) { 7076 IFStateRef ifstate = dynarray_element(&S_ifstate_list, i); 7077 int j; 7078 7079 for (j = 0; j < dynarray_count(&ifstate->services); j++) { 7080 ServiceRef service_p = dynarray_element(&ifstate->services, j); 7081 if (service_p->user_notification == userNotification) { 7082 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 7083 service_p->user_rls, 7084 kCFRunLoopDefaultMode); 7085 my_CFRelease(&service_p->user_rls); 7086 my_CFRelease(&service_p->user_notification); 7087 return; 7088 } 7089 } 7090 } 7091 return; 7092} 7093 7094static CFURLRef 7095copy_icon_url(CFStringRef icon) 7096{ 7097 CFBundleRef np_bundle; 7098 CFURLRef np_url; 7099 CFURLRef url = NULL; 7100 7101#define kNetworkPrefPanePath "/System/Library/PreferencePanes/Network.prefPane" 7102 np_url = CFURLCreateWithFileSystemPath(NULL, 7103 CFSTR(kNetworkPrefPanePath), 7104 kCFURLPOSIXPathStyle, FALSE); 7105 if (np_url != NULL) { 7106 np_bundle = CFBundleCreate(NULL, np_url); 7107 if (np_bundle != NULL) { 7108 url = CFBundleCopyResourceURL(np_bundle, icon, 7109 CFSTR("icns"), NULL); 7110 CFRelease(np_bundle); 7111 } 7112 CFRelease(np_url); 7113 } 7114 return (url); 7115} 7116 7117void 7118ServiceRemoveAddressConflict(ServiceRef service_p) 7119{ 7120 if (service_p->user_rls != NULL) { 7121 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), service_p->user_rls, 7122 kCFRunLoopDefaultMode); 7123 my_CFRelease(&service_p->user_rls); 7124 } 7125 if (service_p->user_notification != NULL) { 7126 CFUserNotificationCancel(service_p->user_notification); 7127 my_CFRelease(&service_p->user_notification); 7128 } 7129 return; 7130} 7131 7132static void 7133service_notify_user(ServiceRef service_p, CFArrayRef header, 7134 CFStringRef message) 7135{ 7136 CFMutableDictionaryRef dict; 7137 SInt32 error; 7138 CFURLRef icon_url; 7139 CFUserNotificationRef notify; 7140 CFRunLoopSourceRef rls; 7141 CFURLRef url; 7142 7143 dict = CFDictionaryCreateMutable(NULL, 0, 7144 &kCFTypeDictionaryKeyCallBacks, 7145 &kCFTypeDictionaryValueCallBacks); 7146 CFDictionarySetValue(dict, kCFUserNotificationAlertHeaderKey, 7147 header); 7148 CFDictionarySetValue(dict, kCFUserNotificationAlertMessageKey, 7149 message); 7150 url = CFBundleCopyBundleURL(S_bundle); 7151 CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey, 7152 url); 7153 CFRelease(url); 7154 icon_url = copy_icon_url(CFSTR("Network")); 7155 if (icon_url != NULL) { 7156 CFDictionarySetValue(dict, kCFUserNotificationIconURLKey, 7157 icon_url); 7158 CFRelease(icon_url); 7159 } 7160 ServiceRemoveAddressConflict(service_p); 7161 CFDictionaryAddValue(dict, 7162 kCFUserNotificationHelpAnchorKey, 7163 CFSTR("mh27606")); 7164 CFDictionaryAddValue(dict, 7165 kCFUserNotificationHelpBookKey, 7166 CFSTR("com.apple.machelp")); 7167 CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, 7168 CFSTR("OK")); 7169 notify = CFUserNotificationCreate(NULL, 0, 0, &error, dict); 7170 CFRelease(dict); 7171 if (notify == NULL) { 7172 my_log(LOG_ERR, "CFUserNotificationCreate() failed, %d", 7173 error); 7174 return; 7175 } 7176 rls = CFUserNotificationCreateRunLoopSource(NULL, notify, 7177 user_confirm, 0); 7178 if (rls == NULL) { 7179 my_log(LOG_ERR, "CFUserNotificationCreateRunLoopSource() failed"); 7180 my_CFRelease(¬ify); 7181 } 7182 else { 7183 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, 7184 kCFRunLoopDefaultMode); 7185 service_p->user_rls = rls; 7186 service_p->user_notification = notify; 7187 } 7188 return; 7189} 7190 7191static void 7192service_report_conflict(ServiceRef service_p, CFStringRef ip_str) 7193{ 7194 CFArrayRef array = NULL; 7195 const void * values[3]; 7196 7197 /* 7198 * CONFLICT_HEADER_BEFORE_IP, CONFLICT_HEADER_AFTER_IP 7199 * 7200 * Unfortunately, we can't just use a format string with %@ because 7201 * the entity that displays the CFUserNotification (CFUN) needs to be able 7202 * to localize the alert strings based on the logged in user's localization. 7203 * If we localize the string here with variable data (the IP address), 7204 * there's no way for the CFUN to localize the string. 7205 * 7206 * The ugly work-around is to break the string into localizable pieces, 7207 * in this case, the string before the IP address, and the string after 7208 * the IP address. 7209 * 7210 * We pass the three pieces { BEFORE_IP, ip_str, AFTER_IP } as an array 7211 * to the CFUN. It will only be able to localize BEFORE_IP and AFTER_IP. 7212 */ 7213 values[0] = CFSTR("CONFLICT_HEADER_BEFORE_IP"); 7214 values[1] = ip_str; 7215 values[2] = CFSTR("CONFLICT_HEADER_AFTER_IP"); 7216 array = CFArrayCreate(NULL, (const void **)values, 3, 7217 &kCFTypeArrayCallBacks); 7218 service_notify_user(service_p, array, CFSTR("CONFLICT_MESSAGE")); 7219 CFRelease(array); 7220 return; 7221} 7222 7223void 7224ServiceReportIPv4AddressConflict(ServiceRef service_p, struct in_addr addr) 7225{ 7226 CFStringRef ip_str = NULL; 7227 7228 ip_str = my_CFStringCreateWithIPAddress(addr); 7229 service_report_conflict(service_p, ip_str); 7230 CFRelease(ip_str); 7231 return; 7232} 7233 7234void 7235ServiceReportIPv6AddressConflict(ServiceRef service_p, 7236 const struct in6_addr * addr_p) 7237{ 7238 CFStringRef ip_str = NULL; 7239 7240 ip_str = my_CFStringCreateWithIPv6Address(addr_p); 7241 service_report_conflict(service_p, ip_str); 7242 CFRelease(ip_str); 7243 return; 7244} 7245 7246#endif /* TARGET_OS_EMBEDDED */ 7247 7248PRIVATE_EXTERN CFStringRef 7249ServiceCopyWakeID(ServiceRef service_p) 7250{ 7251 IFStateRef ifstate = service_ifstate(service_p); 7252 const char * method_string; 7253 7254#define WAKE_ID_FORMAT WAKE_ID_PREFIX ".%s.%s" 7255 method_string = ipconfig_method_string(service_p->method); 7256 return (CFStringCreateWithFormat(NULL, NULL, CFSTR(WAKE_ID_FORMAT), 7257 if_name(ifstate->if_p), 7258 method_string)); 7259} 7260 7261 7262/** 7263 ** Routines to read configuration and convert from CF types to 7264 ** simple types. 7265 **/ 7266static boolean_t 7267S_get_plist_boolean_quiet(CFDictionaryRef plist, CFStringRef key, 7268 boolean_t def) 7269{ 7270 CFBooleanRef b; 7271 boolean_t ret = def; 7272 7273 b = isA_CFBoolean(CFDictionaryGetValue(plist, key)); 7274 if (b) { 7275 ret = CFBooleanGetValue(b); 7276 } 7277 return (ret); 7278} 7279 7280static boolean_t 7281S_get_plist_boolean(CFDictionaryRef plist, CFStringRef key, 7282 boolean_t def) 7283{ 7284 boolean_t ret; 7285 ret = S_get_plist_boolean_quiet(plist, key, def); 7286 if (G_IPConfiguration_verbose) { 7287 my_log(LOG_DEBUG, 7288 "%@ = %s", key, ret == TRUE ? "true" : "false"); 7289 } 7290 return (ret); 7291} 7292 7293static int 7294S_get_plist_int_quiet(CFDictionaryRef plist, CFStringRef key, 7295 int def) 7296{ 7297 CFNumberRef n; 7298 int ret = def; 7299 7300 n = isA_CFNumber(CFDictionaryGetValue(plist, key)); 7301 if (n) { 7302 if (CFNumberGetValue(n, kCFNumberIntType, &ret) == FALSE) { 7303 ret = def; 7304 } 7305 } 7306 return (ret); 7307} 7308 7309static int 7310S_get_plist_int(CFDictionaryRef plist, CFStringRef key, 7311 int def) 7312{ 7313 int ret; 7314 7315 ret = S_get_plist_int_quiet(plist, key, def); 7316 if (G_IPConfiguration_verbose) { 7317 my_log(LOG_DEBUG, "%@ = %d", key, ret); 7318 } 7319 return (ret); 7320} 7321 7322 7323#include <math.h> 7324static struct timeval 7325S_get_plist_timeval(CFDictionaryRef plist, CFStringRef key, 7326 struct timeval def) 7327{ 7328 CFNumberRef n; 7329 struct timeval ret = def; 7330 7331 n = CFDictionaryGetValue(plist, key); 7332 if (n) { 7333 double f; 7334 7335 if (CFNumberGetValue(n, kCFNumberDoubleType, &f) == TRUE) { 7336 ret.tv_sec = (int)floor(f); 7337 ret.tv_usec = (int)((f - floor(f)) * 1000000.0); 7338 } 7339 } 7340 if (G_IPConfiguration_verbose) { 7341 my_log(LOG_DEBUG, 7342 "%@ = %d.%06d", key, ret.tv_sec, 7343 ret.tv_usec); 7344 } 7345 return (ret); 7346} 7347 7348static void * 7349S_get_number_array(CFArrayRef arr, int num_size, int * ret_count) 7350{ 7351 void * buf = NULL; 7352 CFIndex count; 7353 int i; 7354 int real_count = 0; 7355 void * scan; 7356 7357 switch (num_size) { 7358 case 1: 7359 case 2: 7360 case 4: 7361 break; 7362 default: 7363 goto done; 7364 } 7365 count = CFArrayGetCount(arr); 7366 if (count == 0) { 7367 goto done; 7368 } 7369 buf = malloc(count * num_size); 7370 if (buf == NULL) { 7371 goto done; 7372 } 7373 for (i = 0, real_count = 0, scan = buf; i < count; i++) { 7374 CFNumberRef n = isA_CFNumber(CFArrayGetValueAtIndex(arr, i)); 7375 int val; 7376 7377 if (n == NULL 7378 || CFNumberGetValue(n, kCFNumberIntType, &val) == FALSE) { 7379 continue; 7380 } 7381 switch (num_size) { 7382 case 1: 7383 *((uint8_t *)scan) = val; 7384 break; 7385 case 2: 7386 *((uint16_t *)scan) = val; 7387 break; 7388 case 4: 7389 *((uint32_t *)scan) = val; 7390 break; 7391 default: 7392 break; 7393 } 7394 real_count++; 7395 scan += num_size; 7396 } 7397 done: 7398 *ret_count = real_count; 7399 if (real_count == 0 && buf != NULL) { 7400 free(buf); 7401 buf = NULL; 7402 } 7403 return (buf); 7404} 7405 7406static void * 7407S_get_plist_number_array(CFDictionaryRef plist, CFStringRef key, 7408 int num_size, int * ret_count) 7409{ 7410 CFArrayRef a; 7411 7412 a = isA_CFArray(CFDictionaryGetValue(plist, key)); 7413 if (a == NULL) { 7414 return (NULL); 7415 } 7416 return (S_get_number_array(a, num_size, ret_count)); 7417} 7418 7419static uint8_t * 7420S_get_plist_uint8_array(CFDictionaryRef plist, CFStringRef key, 7421 int * ret_count) 7422{ 7423 return (S_get_plist_number_array(plist, key, sizeof(uint8_t), ret_count)); 7424} 7425 7426static uint16_t * 7427S_get_plist_uint16_array(CFDictionaryRef plist, CFStringRef key, 7428 int * ret_count) 7429{ 7430 return (S_get_plist_number_array(plist, key, sizeof(uint16_t), ret_count)); 7431} 7432 7433static void 7434my_CFNumberAddUniqueToArray(CFNumberRef number, CFMutableArrayRef merge) 7435{ 7436 number = isA_CFNumber(number); 7437 if (number == NULL) { 7438 return; 7439 } 7440 my_CFArrayAppendUniqueValue(merge, number); 7441} 7442 7443static void 7444merge_arrays(const void *key, const void *value, void *context) 7445{ 7446 CFArrayRef arr; 7447 CFDictionaryRef dict; 7448 CFMutableArrayRef merge = (CFMutableArrayRef)context; 7449 7450 dict = isA_CFDictionary(value); 7451 if (dict == NULL) { 7452 return; 7453 } 7454 arr = CFDictionaryGetValue(dict, 7455 kDHCPRequestedParameterList); 7456 if (isA_CFArray(arr) == NULL) { 7457 return; 7458 } 7459 CFArrayApplyFunction(arr, CFRangeMake(0, CFArrayGetCount(arr)), 7460 (CFArrayApplierFunction)my_CFNumberAddUniqueToArray, 7461 merge); 7462 return; 7463} 7464 7465static CFArrayRef 7466applicationRequestedParametersCopy(SCPreferencesRef prefs) 7467{ 7468 CFPropertyListRef data = NULL; 7469 CFMutableArrayRef array = NULL; 7470 7471 data = SCPreferencesGetValue(prefs, kDHCPClientApplicationPref); 7472 if (isA_CFDictionary(data) == NULL) { 7473 goto done; 7474 } 7475 if (G_IPConfiguration_verbose) { 7476 my_log(LOG_DEBUG, "dictionary is %@", data); 7477 } 7478 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 7479 if (array == NULL) { 7480 goto done; 7481 } 7482 CFDictionaryApplyFunction(data, merge_arrays, array); 7483 if (CFArrayGetCount(array) == 0) { 7484 CFRelease(array); 7485 array = NULL; 7486 } 7487 7488 done: 7489 return (array); 7490} 7491 7492static void 7493S_set_globals(void) 7494{ 7495 uint8_t * dhcp_params = NULL; 7496 CFDictionaryRef info_dict; 7497 int n_dhcp_params = 0; 7498 CFDictionaryRef plist; 7499 7500 if (S_bundle == NULL) { 7501 return; 7502 } 7503 info_dict = CFBundleGetInfoDictionary(S_bundle); 7504 if (info_dict == NULL) { 7505 return; 7506 } 7507 plist = CFDictionaryGetValue(info_dict, CFSTR("IPConfiguration")); 7508 if (isA_CFDictionary(plist) == NULL) { 7509 return; 7510 } 7511 G_must_broadcast 7512 = S_get_plist_boolean(plist, CFSTR("MustBroadcast"), FALSE); 7513 G_max_retries = S_get_plist_int(plist, CFSTR("RetryCount"), 7514 MAX_RETRIES); 7515 G_gather_secs = S_get_plist_int(plist, CFSTR("GatherTimeSeconds"), 7516 GATHER_SECS); 7517 S_link_inactive_secs 7518 = S_get_plist_timeval(plist, CFSTR("LinkInactiveWaitTimeSeconds"), 7519 S_link_inactive_secs); 7520 G_initial_wait_secs 7521 = S_get_plist_int(plist, CFSTR("InitialRetryTimeSeconds"), 7522 INITIAL_WAIT_SECS); 7523 G_max_wait_secs 7524 = S_get_plist_int(plist, CFSTR("MaximumRetryTimeSeconds"), 7525 MAX_WAIT_SECS); 7526 S_arp_probe_count 7527 = S_get_plist_int(plist, CFSTR("ARPProbeCount"), 7528 ARP_PROBE_COUNT); 7529 S_arp_gratuitous_count 7530 = S_get_plist_int(plist, CFSTR("ARPGratuitousCount"), 7531 ARP_GRATUITOUS_COUNT); 7532 S_arp_retry 7533 = S_get_plist_timeval(plist, CFSTR("ARPRetryTimeSeconds"), 7534 S_arp_retry); 7535 S_arp_detect_count 7536 = S_get_plist_int(plist, CFSTR("ARPDetectCount"), 7537 ARP_DETECT_COUNT); 7538 S_arp_detect_retry 7539 = S_get_plist_timeval(plist, CFSTR("ARPDetectRetryTimeSeconds"), 7540 S_arp_detect_retry); 7541 S_arp_resolve_retry 7542 = S_get_plist_timeval(plist, CFSTR("ARPResolveRetryTimeSeconds"), 7543 S_arp_resolve_retry); 7544 G_dhcp_accepts_bootp 7545 = S_get_plist_boolean(plist, CFSTR("DHCPAcceptsBOOTP"), FALSE); 7546 G_dhcp_failure_configures_linklocal 7547 = S_get_plist_boolean(plist, 7548 CFSTR("DHCPFailureConfiguresLinkLocal"), 7549 DHCP_FAILURE_CONFIGURES_LINKLOCAL); 7550 G_dhcp_success_deconfigures_linklocal 7551 = S_get_plist_boolean(plist, 7552 CFSTR("DHCPSuccessDeconfiguresLinkLocal"), 7553 DHCP_SUCCESS_DECONFIGURES_LINKLOCAL); 7554 G_dhcp_init_reboot_retry_count 7555 = S_get_plist_int(plist, CFSTR("DHCPInitRebootRetryCount"), 7556 DHCP_INIT_REBOOT_RETRY_COUNT); 7557 G_dhcp_select_retry_count 7558 = S_get_plist_int(plist, CFSTR("DHCPSelectRetryCount"), 7559 DHCP_SELECT_RETRY_COUNT); 7560 G_dhcp_allocate_linklocal_at_retry_count 7561 = S_get_plist_int(plist, CFSTR("DHCPAllocateLinkLocalAtRetryCount"), 7562 DHCP_ALLOCATE_LINKLOCAL_AT_RETRY_COUNT); 7563 G_dhcp_router_arp_at_retry_count 7564 = S_get_plist_int(plist, CFSTR("DHCPRouterARPAtRetryCount"), 7565 DHCP_ROUTER_ARP_AT_RETRY_COUNT); 7566 dhcp_params 7567 = S_get_plist_uint8_array(plist, 7568 kDHCPRequestedParameterList, 7569 &n_dhcp_params); 7570 dhcp_set_default_parameters(dhcp_params, n_dhcp_params); 7571 G_router_arp 7572 = S_get_plist_boolean(plist, CFSTR("RouterARPEnabled"), TRUE); 7573 7574 G_router_arp_wifi_lease_start_threshold_secs 7575 = S_get_plist_int(plist, 7576 CFSTR("RouterARPWiFiLeaseStartThresholdSeconds"), 7577 G_router_arp_wifi_lease_start_threshold_secs); 7578 7579 S_dhcp_local_hostname_length_max 7580 = S_get_plist_int(plist, CFSTR("DHCPLocalHostNameLengthMax"), 7581 DHCP_LOCAL_HOSTNAME_LENGTH_MAX); 7582 G_discover_and_publish_router_mac_address 7583 = S_get_plist_boolean(plist, 7584 CFSTR("DiscoverAndPublishRouterMACAddress"), 7585 TRUE); 7586 S_discover_router_mac_address_secs 7587 = S_get_plist_int(plist, 7588 CFSTR("DiscoverRouterMACAddressTimeSeconds"), 7589 DISCOVER_ROUTER_MAC_ADDRESS_SECS); 7590 S_defend_ip_address_interval_secs 7591 = S_get_plist_int(plist, 7592 CFSTR("DefendIPAddressIntervalSeconds"), 7593 DEFEND_IP_ADDRESS_INTERVAL_SECS); 7594 S_defend_ip_address_count 7595 = S_get_plist_int(plist, 7596 CFSTR("DefendIPAddressCount"), 7597 DEFEND_IP_ADDRESS_COUNT); 7598 G_dhcp_lease_write_t1_threshold_secs 7599 = S_get_plist_int(plist, 7600 CFSTR("DHCPLeaseWriteT1ThresholdSeconds"), 7601 DHCP_LEASE_WRITE_T1_THRESHOLD_SECS); 7602 S_arp_conflict_retry 7603 = S_get_plist_int(plist, 7604 CFSTR("ARPConflictRetryCount"), 7605 ARP_CONFLICT_RETRY_COUNT); 7606 S_arp_conflict_delay 7607 = S_get_plist_timeval(plist, CFSTR("ARPConflictRetryDelaySeconds"), 7608 S_arp_conflict_delay); 7609 G_manual_conflict_retry_interval_secs 7610 = S_get_plist_int(plist, 7611 CFSTR("ManualConflictRetryIntervalSeconds"), 7612 MANUAL_CONFLICT_RETRY_INTERVAL_SECS); 7613 G_min_short_wake_interval_secs 7614 = S_get_plist_int(plist, 7615 CFSTR("MinimumShortWakeIntervalSeconds"), 7616 MIN_SHORT_WAKE_INTERVAL_SECS); 7617 G_min_wake_interval_secs 7618 = S_get_plist_int(plist, 7619 CFSTR("MinimumWakeIntervalSeconds"), 7620 MIN_WAKE_INTERVAL_SECS); 7621 G_wake_skew_secs 7622 = S_get_plist_int(plist, 7623 CFSTR("WakeSkewSeconds"), 7624 WAKE_SKEW_SECS); 7625#if ! TARGET_OS_EMBEDDED 7626 S_use_maintenance_wake 7627 = S_get_plist_boolean(plist, 7628 CFSTR("UseMaintenanceWake"), 7629 TRUE); 7630#endif /* ! TARGET_OS_EMBEDDED */ 7631 S_configure_ipv6 = S_get_plist_boolean(plist, 7632 CFSTR("ConfigureIPv6"), 7633 TRUE); 7634 if (S_configure_ipv6) { 7635 uint16_t * dhcpv6_options; 7636 int dhcpv6_options_count; 7637 7638 G_dhcpv6_enabled = S_get_plist_boolean(plist, 7639 CFSTR("DHCPv6Enabled"), 7640 DHCPv6_ENABLED); 7641 dhcpv6_options = S_get_plist_uint16_array(plist, 7642 kDHCPv6RequestedOptions, 7643 &dhcpv6_options_count); 7644 DHCPv6ClientSetRequestedOptions(dhcpv6_options, 7645 dhcpv6_options_count); 7646 G_dhcpv6_stateful_enabled = S_get_plist_boolean(plist, 7647 CFSTR("DHCPv6StatefulEnabled"), 7648 DHCPv6_STATEFUL_ENABLED); 7649 G_dhcp_duid_type = S_get_plist_int(plist, 7650 CFSTR("DHCPDUIDType"), 7651 kDHCPDUIDTypeLLT); 7652 switch (G_dhcp_duid_type) { 7653 case kDHCPDUIDTypeLLT: 7654 case kDHCPDUIDTypeLL: 7655 /* supported */ 7656 break; 7657 default: 7658 /* unsupported, use default (LLT) */ 7659 G_dhcp_duid_type = kDHCPDUIDTypeLLT; 7660 break; 7661 } 7662 } 7663 return; 7664} 7665 7666static void 7667S_add_dhcp_parameters(SCPreferencesRef prefs) 7668{ 7669 uint8_t * dhcp_params = NULL; 7670 int n_dhcp_params = 0; 7671 CFArrayRef rp = applicationRequestedParametersCopy(prefs); 7672 7673 if (rp != NULL) { 7674 dhcp_params = S_get_number_array(rp, sizeof(*dhcp_params), 7675 &n_dhcp_params); 7676 my_CFRelease(&rp); 7677 } 7678 dhcp_set_additional_parameters(dhcp_params, n_dhcp_params); 7679 return; 7680} 7681 7682STATIC void 7683check_verbose(SCPreferencesRef prefs) 7684{ 7685 Boolean verbose; 7686 7687 verbose = IPConfigurationControlPrefsGetVerbose(); 7688 if (G_IPConfiguration_verbose != verbose) { 7689 G_IPConfiguration_verbose = verbose; 7690 if (verbose) { 7691 IPConfigurationLogSetVerbose(verbose); 7692 my_log(LOG_NOTICE, "IPConfiguration: verbose mode enabled"); 7693 } 7694 else { 7695 my_log(LOG_NOTICE, "IPConfiguration: verbose mode disabled"); 7696 IPConfigurationLogSetVerbose(verbose); 7697 } 7698 bootp_session_set_verbose(verbose); 7699 DHCPv6SocketSetVerbose(verbose); 7700 } 7701 IPConfigurationControlPrefsSynchronize(); 7702 return; 7703} 7704 7705void 7706load(CFBundleRef bundle, Boolean bundleVerbose) 7707{ 7708 S_bundle = (CFBundleRef)CFRetain(bundle); 7709 return; 7710} 7711 7712void 7713start(const char *bundleName, const char *bundleDir) 7714{ 7715 arp_session_values_t arp_values; 7716 SCPreferencesRef prefs = NULL; 7717 7718 /* register for verbose logging changes, check current verbose state */ 7719 check_verbose(IPConfigurationControlPrefsInit(CFRunLoopGetCurrent(), 7720 check_verbose)); 7721 /* create paths */ 7722 ipconfigd_create_paths(); 7723 7724 /* initialize CGA */ 7725 CGAInit(); 7726 7727 /* set globals */ 7728 S_set_globals(); 7729 prefs = SCPreferencesCreate(NULL, CFSTR("IPConfiguration.DHCPClient"), 7730 kDHCPClientPreferencesID); 7731 if (prefs == NULL) { 7732 my_log(LOG_ERR, 7733 "IPConfiguration: SCPreferencesCreate failed: %s", 7734 SCErrorString(SCError())); 7735 return; 7736 } 7737 if (SCPreferencesSetCallback(prefs, 7738 dhcp_preferences_changed, 7739 NULL) == FALSE 7740 || SCPreferencesScheduleWithRunLoop(prefs, 7741 CFRunLoopGetCurrent(), 7742 kCFRunLoopDefaultMode) == FALSE) { 7743 my_log(LOG_ERR, "IPConfigurationSCPreferencesSetCallback failed: %s", 7744 SCErrorString(SCError())); 7745 my_CFRelease(&prefs); 7746 return; 7747 } 7748 S_add_dhcp_parameters(prefs); 7749 SCPreferencesSynchronize(prefs); 7750 7751 S_scd_session = SCDynamicStoreCreate(NULL, 7752 CFSTR("IPConfiguration"), 7753 handle_change, NULL); 7754 if (S_scd_session == NULL) { 7755 S_scd_session = NULL; 7756 my_log(LOG_ERR, "SCDynamicStoreCreate failed: %s", 7757 SCErrorString(SCError())); 7758 } 7759 7760 G_bootp_session = bootp_session_init(G_client_port); 7761 if (G_bootp_session == NULL) { 7762 my_log(LOG_DEBUG, "bootp_session_init() failed"); 7763 return; 7764 } 7765 7766 /* initialize the default values structure */ 7767 bzero(&arp_values, sizeof(arp_values)); 7768 arp_values.probe_count = &S_arp_probe_count; 7769 arp_values.probe_gratuitous_count = &S_arp_gratuitous_count; 7770 arp_values.probe_interval = &S_arp_retry; 7771 arp_values.detect_count = &S_arp_detect_count; 7772 arp_values.detect_interval = &S_arp_detect_retry; 7773 arp_values.conflict_retry_count = &S_arp_conflict_retry; 7774 arp_values.conflict_delay_interval = &S_arp_conflict_delay; 7775 arp_values.resolve_interval = &S_arp_resolve_retry; 7776 G_arp_session = arp_session_init(S_is_our_hardware_address, 7777 &arp_values); 7778 if (G_arp_session == NULL) { 7779 my_log(LOG_DEBUG, "arp_session_init() failed"); 7780 return; 7781 } 7782 dynarray_init(&S_ifstate_list, IFState_free, NULL); 7783 7784 CleanupWakeEvents(); 7785 7786 /* set the loopback interface address */ 7787 set_loopback(); 7788 return; 7789} 7790 7791void 7792prime() 7793{ 7794 if (G_bootp_session == NULL) { 7795 return; 7796 } 7797 if (S_scd_session == NULL) { 7798 update_interface_list(); 7799 } 7800 else { 7801 /* begin interface initialization */ 7802 start_initialization(S_scd_session); 7803 } 7804 7805 /* initialize the MiG server */ 7806 server_init(); 7807} 7808 7809void 7810stop(CFRunLoopSourceRef stopRls) 7811{ 7812 if (G_bootp_session != NULL) { 7813 IFStateList_all_services_event(&S_ifstate_list, 7814 IFEventID_power_off_e, NULL); 7815 } 7816 CFRunLoopSourceSignal(stopRls); 7817} 7818