2 * Copyright (c) 2002-2007, 2011, 2013, 2015-2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * October 21, 2000 Allan Nathanson <ajn@apple.com>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
38 #include <net/if_media.h>
40 #define SC_LOG_HANDLE __log_LinkConfiguration()
41 #define SC_LOG_HANDLE_TYPE static
42 #include "SCNetworkConfigurationInternal.h"
43 #include <SystemConfiguration/SCDPlugin.h> // for _SCDPluginExecCommand
46 static CFMutableDictionaryRef baseSettings
= NULL
;
47 static CFStringRef interfacesKey
= NULL
;
48 static SCDynamicStoreRef store
= NULL
;
49 static CFRunLoopSourceRef rls
= NULL
;
50 static CFMutableDictionaryRef wantSettings
= NULL
;
58 __log_LinkConfiguration(void)
60 static os_log_t log
= NULL
;
63 log
= os_log_create("com.apple.SystemConfiguration", "LinkConfiguration");
71 #pragma mark Capabilities
74 #define CAPABILITIES_KEY CFSTR("_CAPABILITIES_")
79 _SCNetworkInterfaceSetCapabilities(SCNetworkInterfaceRef interface
,
80 CFDictionaryRef options
)
82 CFDictionaryRef baseOptions
;
86 CFStringRef interfaceName
;
94 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
95 if (interfaceName
== NULL
) {
96 /* if no BSD interface name */
100 cap_current
= __SCNetworkInterfaceCreateCapabilities(interface
, -1, NULL
);
101 if (cap_current
== -1) {
102 /* could not get current capabilities */
106 // get base capabilities
107 cap_base
= cap_current
;
108 baseOptions
= CFDictionaryGetValue(baseSettings
, interfaceName
);
109 if (baseOptions
!= NULL
) {
112 num
= CFDictionaryGetValue(baseOptions
, CAPABILITIES_KEY
);
114 CFNumberGetValue(num
, kCFNumberIntType
, &cap_base
);
118 cap_requested
= __SCNetworkInterfaceCreateCapabilities(interface
, cap_base
, options
);
121 if (cap_requested
== cap_current
) {
122 /* if current setting is as requested */
126 bzero((char *)&ifr
, sizeof(ifr
));
127 (void)_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
128 ifr
.ifr_curcap
= cap_current
;
129 ifr
.ifr_reqcap
= cap_requested
;
131 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
133 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
137 ret
= ioctl(sock
, SIOCSIFCAP
, (caddr_t
)&ifr
);
140 SC_log(LOG_ERR
, "%@: ioctl(SIOCSIFCAP) failed: %s", interfaceName
, strerror(errno
));
150 #pragma mark Media options
153 static CFDictionaryRef
154 __copyMediaOptions(CFDictionaryRef options
)
156 CFMutableDictionaryRef requested
= NULL
;
159 if (!isA_CFDictionary(options
)) {
163 val
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
164 if (isA_CFString(val
)) {
165 requested
= CFDictionaryCreateMutable(NULL
,
167 &kCFTypeDictionaryKeyCallBacks
,
168 &kCFTypeDictionaryValueCallBacks
);
169 CFDictionaryAddValue(requested
, kSCPropNetEthernetMediaSubType
, val
);
175 val
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
176 if (isA_CFArray(val
)) {
177 CFDictionaryAddValue(requested
, kSCPropNetEthernetMediaOptions
, val
);
180 CFRelease(requested
);
190 _SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface
,
191 CFDictionaryRef options
)
193 CFArrayRef available
= NULL
;
194 CFDictionaryRef current
= NULL
;
195 struct ifmediareq ifm
;
197 CFStringRef interfaceName
;
200 CFDictionaryRef requested
;
203 if (!isA_SCNetworkInterface(interface
)) {
204 _SCErrorSet(kSCStatusInvalidArgument
);
208 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
209 if (interfaceName
== NULL
) {
210 /* if no BSD interface name */
211 SC_log(LOG_INFO
, "no BSD interface name for %@", interface
);
212 _SCErrorSet(kSCStatusInvalidArgument
);
216 /* get current & available options */
217 if (!SCNetworkInterfaceCopyMediaOptions(interface
, ¤t
, NULL
, &available
, FALSE
)) {
218 /* could not get current media options */
219 SC_log(LOG_INFO
, "no media options for %@", interfaceName
);
223 /* extract just the dictionary key/value pairs of interest */
224 requested
= __copyMediaOptions(options
);
225 if (requested
== NULL
) {
226 CFDictionaryRef baseOptions
;
228 /* get base options */
229 baseOptions
= CFDictionaryGetValue(baseSettings
, interfaceName
);
230 requested
= __copyMediaOptions(baseOptions
);
232 if (requested
== NULL
) {
233 /* get base options */
234 requested
= __copyMediaOptions(current
);
236 if (requested
== NULL
) {
237 /* if no media options to set */
241 if ((current
!= NULL
) && CFEqual(current
, requested
)) {
242 /* if current settings are as requested */
247 if (!CFArrayContainsValue(available
, CFRangeMake(0, CFArrayGetCount(available
)), requested
)) {
248 /* if requested settings not currently available */
249 SC_log(LOG_INFO
, "requested media settings unavailable for %@", interfaceName
);
253 newOptions
= __SCNetworkInterfaceCreateMediaOptions(interface
, requested
);
254 if (newOptions
== -1) {
255 /* since we have just validated, this should never happen */
259 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
261 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
265 bzero((char *)&ifm
, sizeof(ifm
));
266 (void)_SC_cfstring_to_cstring(interfaceName
, ifm
.ifm_name
, sizeof(ifm
.ifm_name
), kCFStringEncodingASCII
);
268 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
269 SC_log(LOG_ERR
, "%@: ioctl(SIOCGIFMEDIA) failed: %s", interfaceName
, strerror(errno
));
273 bzero((char *)&ifr
, sizeof(ifr
));
274 bcopy(ifm
.ifm_name
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
));
275 ifr
.ifr_media
= ifm
.ifm_current
& ~(IFM_NMASK
|IFM_TMASK
|IFM_OMASK
|IFM_GMASK
);
276 ifr
.ifr_media
|= newOptions
;
278 SC_log(LOG_INFO
, "old media settings: 0x%8.8x (0x%8.8x)", ifm
.ifm_current
, ifm
.ifm_active
);
279 SC_log(LOG_INFO
, "new media settings: 0x%8.8x", ifr
.ifr_media
);
281 if (ioctl(sock
, SIOCSIFMEDIA
, (caddr_t
)&ifr
) == -1) {
282 SC_log(LOG_ERR
, "%@: ioctl(SIOCSIFMEDIA) failed: %s", interfaceName
, strerror(errno
));
290 if (available
!= NULL
) CFRelease(available
);
291 if (current
!= NULL
) CFRelease(current
);
292 if (requested
!= NULL
) CFRelease(requested
);
293 if (sock
!= -1) (void)close(sock
);
303 #ifndef USE_SIOCSIFMTU
305 ifconfig_exit(pid_t pid
, int status
, struct rusage
*rusage
, void *context
)
308 #pragma unused(rusage)
309 char *if_name
= (char *)context
;
311 if (WIFEXITED(status
)) {
312 if (WEXITSTATUS(status
) != 0) {
313 SC_log(LOG_NOTICE
, "ifconfig %s failed, exit status = %d",
315 WEXITSTATUS(status
));
317 } else if (WIFSIGNALED(status
)) {
318 SC_log(LOG_NOTICE
, "ifconfig %s: terminated w/signal = %d",
322 SC_log(LOG_NOTICE
, "ifconfig %s: exit status = %d",
327 CFAllocatorDeallocate(NULL
, if_name
);
330 #endif /* !USE_SIOCSIFMTU */
335 _SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface
,
336 CFDictionaryRef options
)
338 CFArrayRef bridge_members
= NULL
;
339 Boolean bridge_updated
= FALSE
;
340 CFStringRef interfaceName
;
341 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
342 CFStringRef interfaceType
;
350 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
351 if (interfaceName
== NULL
) {
352 /* if no BSD interface name */
356 if (!SCNetworkInterfaceCopyMTU(interface
, &mtu_cur
, &mtu_min
, &mtu_max
)) {
357 /* could not get current MTU */
362 if (isA_CFDictionary(options
)) {
363 val
= CFDictionaryGetValue(options
, kSCPropNetEthernetMTU
);
364 val
= isA_CFNumber(val
);
367 CFDictionaryRef baseOptions
;
370 baseOptions
= CFDictionaryGetValue(baseSettings
, interfaceName
);
371 if (baseOptions
!= NULL
) {
372 val
= CFDictionaryGetValue(baseOptions
, kSCPropNetEthernetMTU
);
376 CFNumberGetValue(val
, kCFNumberIntType
, &requested
);
381 if (requested
== mtu_cur
) {
382 /* if current setting is as requested */
386 if (((mtu_min
>= 0) && (requested
< mtu_min
)) ||
387 ((mtu_max
>= 0) && (requested
> mtu_max
))) {
388 /* if requested MTU outside of the valid range */
392 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
393 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeBridge
)) {
394 bridge_members
= SCBridgeInterfaceGetMemberInterfaces(interface
);
395 if ((bridge_members
!= NULL
) && (CFArrayGetCount(bridge_members
) == 0)) {
397 bridge_members
= NULL
;
399 if (bridge_members
!= NULL
) {
400 SCNetworkInterfaceRef member0
;
402 /* temporarily, remove all bridge members */
403 CFRetain(bridge_members
);
404 ok
= SCBridgeInterfaceSetMemberInterfaces(interface
, NULL
);
409 /* and update the (bridge) configuration */
410 ok
= _SCBridgeInterfaceUpdateConfiguration(interfacePrivate
->prefs
);
415 /* switch from updating the MTU of the bridge to the first member */
416 member0
= CFArrayGetValueAtIndex(bridge_members
, 0);
417 interfaceName
= SCNetworkInterfaceGetBSDName(member0
);
419 bridge_updated
= TRUE
;
423 #ifdef USE_SIOCSIFMTU
429 bzero((char *)&ifr
, sizeof(ifr
));
430 (void)_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
431 ifr
.ifr_mtu
= requested
;
433 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
435 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
440 ret
= ioctl(sock
, SIOCSIFMTU
, (caddr_t
)&ifr
);
443 SC_log(LOG_ERR
, "%@: ioctl(SIOCSIFMTU) failed: %s", interfaceName
, strerror(errno
));
448 #else /* !USE_SIOCSIFMTU */
450 char *ifconfig_argv
[] = { "ifconfig", NULL
, "mtu", NULL
, NULL
};
453 ifconfig_argv
[1] = _SC_cfstring_to_cstring(interfaceName
, NULL
, 0, kCFStringEncodingASCII
);
454 (void)asprintf(&ifconfig_argv
[3], "%d", requested
);
456 pid
= _SCDPluginExecCommand(ifconfig_exit
, // callout,
457 ifconfig_argv
[1], // context
460 "/sbin/ifconfig", // path
461 ifconfig_argv
// argv
464 // CFAllocatorDeallocate(NULL, ifconfig_argv[1]); // released in ifconfig_exit()
465 free(ifconfig_argv
[3]);
472 #endif /* !USE_SIOCSIFMTU */
476 if (bridge_members
!= NULL
) {
477 /* restore bridge members */
478 (void) SCBridgeInterfaceSetMemberInterfaces(interface
, bridge_members
);
479 CFRelease(bridge_members
);
481 if (bridge_updated
) {
482 /* and update the (bridge) configuration */
483 (void) _SCBridgeInterfaceUpdateConfiguration(interfacePrivate
->prefs
);
492 #pragma mark Update link configuration
496 * Function: parse_component
498 * Given a string 'key' and a string prefix 'prefix',
499 * return the next component in the slash '/' separated
503 * 1. key = "a/b/c" prefix = "a/"
505 * 2. key = "a/b/c" prefix = "a/b/"
508 static CF_RETURNS_RETAINED CFStringRef
509 parse_component(CFStringRef key
, CFStringRef prefix
)
511 CFMutableStringRef comp
;
514 if (!CFStringHasPrefix(key
, prefix
)) {
517 comp
= CFStringCreateMutableCopy(NULL
, 0, key
);
518 CFStringDelete(comp
, CFRangeMake(0, CFStringGetLength(prefix
)));
519 range
= CFStringFind(comp
, CFSTR("/"), 0);
520 if (range
.location
== kCFNotFound
) {
523 range
.length
= CFStringGetLength(comp
) - range
.location
;
524 CFStringDelete(comp
, range
);
529 static void updateLink(CFStringRef interfaceName
, CFDictionaryRef options
);
533 updateInterfaces(CFArrayRef newInterfaces
)
538 static CFArrayRef oldInterfaces
= NULL
;
540 n_old
= (oldInterfaces
!= NULL
) ? CFArrayGetCount(oldInterfaces
) : 0;
541 n_new
= CFArrayGetCount(newInterfaces
);
543 for (i
= 0; i
< n_new
; i
++) {
544 CFStringRef interfaceName
;
546 interfaceName
= CFArrayGetValueAtIndex(newInterfaces
, i
);
549 !CFArrayContainsValue(oldInterfaces
,
550 CFRangeMake(0, n_old
),
552 CFDictionaryRef options
;
555 options
= CFDictionaryGetValue(wantSettings
, interfaceName
);
556 updateLink(interfaceName
, options
);
560 if (oldInterfaces
!= NULL
) CFRelease(oldInterfaces
);
561 oldInterfaces
= CFRetain(newInterfaces
);
566 updateLink(CFStringRef interfaceName
, CFDictionaryRef options
)
568 SCNetworkInterfaceRef interface
;
570 /* retain requested configuration */
571 if (options
!= NULL
) {
572 CFDictionarySetValue(wantSettings
, interfaceName
, options
);
574 CFDictionaryRemoveValue(wantSettings
, interfaceName
);
577 /* apply requested configuration */
578 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, interfaceName
,
579 kIncludeAllVirtualInterfaces
);
580 if (interface
== NULL
) {
584 if (options
!= NULL
) {
585 if (!CFDictionaryContainsKey(baseSettings
, interfaceName
)) {
587 CFDictionaryRef cur_media
= NULL
;
588 CFMutableDictionaryRef new_media
= NULL
;
591 /* preserve current media options */
592 if (SCNetworkInterfaceCopyMediaOptions(interface
, &cur_media
, NULL
, NULL
, FALSE
)) {
593 if (cur_media
!= NULL
) {
594 new_media
= CFDictionaryCreateMutableCopy(NULL
, 0, cur_media
);
595 CFRelease(cur_media
);
599 /* preserve current MTU */
600 if (SCNetworkInterfaceCopyMTU(interface
, &cur_mtu
, NULL
, NULL
)) {
604 if (new_media
== NULL
) {
605 new_media
= CFDictionaryCreateMutable(NULL
,
607 &kCFTypeDictionaryKeyCallBacks
,
608 &kCFTypeDictionaryValueCallBacks
);
611 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &cur_mtu
);
612 CFDictionaryAddValue(new_media
, kSCPropNetEthernetMTU
, num
);
617 /* preserve capabilities */
618 cur_cap
= __SCNetworkInterfaceCreateCapabilities(interface
, -1, NULL
);
622 if (new_media
== NULL
) {
623 new_media
= CFDictionaryCreateMutable(NULL
,
625 &kCFTypeDictionaryKeyCallBacks
,
626 &kCFTypeDictionaryValueCallBacks
);
629 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &cur_cap
);
630 CFDictionaryAddValue(new_media
, CAPABILITIES_KEY
, num
);
634 if (new_media
!= NULL
) {
635 CFDictionarySetValue(baseSettings
, interfaceName
, new_media
);
636 CFRelease(new_media
);
640 /* establish new settings */
641 (void)_SCNetworkInterfaceSetCapabilities(interface
, options
);
642 (void)_SCNetworkInterfaceSetMediaOptions(interface
, options
);
643 (void)_SCNetworkInterfaceSetMTU (interface
, options
);
645 /* no requested settings */
646 options
= CFDictionaryGetValue(baseSettings
, interfaceName
);
647 if (options
!= NULL
) {
648 /* restore original settings */
649 (void)_SCNetworkInterfaceSetCapabilities(interface
, options
);
650 (void)_SCNetworkInterfaceSetMediaOptions(interface
, options
);
651 (void)_SCNetworkInterfaceSetMTU (interface
, options
);
652 CFDictionaryRemoveValue(baseSettings
, interfaceName
);
656 CFRelease(interface
);
662 linkConfigChangedCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *arg
)
665 os_activity_t activity
;
666 CFDictionaryRef changes
;
669 static CFStringRef prefix
= NULL
;
671 activity
= os_activity_create("processing link configuration changes",
673 OS_ACTIVITY_FLAG_DEFAULT
);
674 os_activity_scope(activity
);
676 if (prefix
== NULL
) {
677 prefix
= SCDynamicStoreKeyCreate(NULL
,
679 kSCDynamicStoreDomainSetup
,
684 changes
= SCDynamicStoreCopyMultiple(store
, changedKeys
, NULL
);
686 n
= (changes
!= NULL
) ? CFArrayGetCount(changedKeys
) : 0;
687 for (i
= 0; i
< n
; i
++) {
689 CFDictionaryRef info
;
691 key
= CFArrayGetValueAtIndex(changedKeys
, i
);
692 info
= CFDictionaryGetValue(changes
, key
);
694 if (CFEqual(key
, interfacesKey
)) {
695 if (isA_CFDictionary(info
) != NULL
) {
696 CFArrayRef interfaces
;
698 interfaces
= CFDictionaryGetValue(info
, kSCPropNetInterfaces
);
699 if (isA_CFArray(interfaces
)) {
700 updateInterfaces(interfaces
);
704 CFStringRef interfaceName
;
706 interfaceName
= parse_component(key
, prefix
);
707 if (interfaceName
!= NULL
) {
708 updateLink(interfaceName
, info
);
709 CFRelease(interfaceName
);
714 if (changes
!= NULL
) {
718 os_release(activity
);
726 load_LinkConfiguration(CFBundleRef bundle
, Boolean bundleVerbose
)
728 #pragma unused(bundleVerbose)
730 CFMutableArrayRef keys
= NULL
;
732 CFMutableArrayRef patterns
= NULL
;
734 SC_log(LOG_DEBUG
, "load() called");
735 SC_log(LOG_DEBUG
, " bundle ID = %@", CFBundleGetIdentifier(bundle
));
737 /* initialize a few globals */
739 baseSettings
= CFDictionaryCreateMutable(NULL
,
741 &kCFTypeDictionaryKeyCallBacks
,
742 &kCFTypeDictionaryValueCallBacks
);
743 wantSettings
= CFDictionaryCreateMutable(NULL
,
745 &kCFTypeDictionaryKeyCallBacks
,
746 &kCFTypeDictionaryValueCallBacks
);
748 /* open a "configd" store to allow cache updates */
749 store
= SCDynamicStoreCreate(NULL
,
750 CFSTR("Link Configuraton plug-in"),
751 linkConfigChangedCallback
,
754 SC_log(LOG_ERR
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
758 /* establish notification keys and patterns */
759 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
760 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
762 /* ...watch for a change in the list of network interfaces */
763 interfacesKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
764 kSCDynamicStoreDomainState
);
765 CFArrayAppendValue(keys
, interfacesKey
);
767 /* ...watch for (per-interface) AirPort configuration changes */
768 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
769 kSCDynamicStoreDomainSetup
,
772 CFArrayAppendValue(patterns
, key
);
775 /* ...watch for (per-interface) Ethernet configuration changes */
776 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
777 kSCDynamicStoreDomainSetup
,
780 CFArrayAppendValue(patterns
, key
);
784 /* ...watch for (per-interface) FireWire configuration changes */
785 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
786 kSCDynamicStoreDomainSetup
,
789 CFArrayAppendValue(patterns
, key
);
791 #endif // TARGET_OS_OSX
793 /* register the keys/patterns */
794 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
);
798 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed: %s",
799 SCErrorString(SCError()));
803 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
805 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed: %s",
806 SCErrorString(SCError()));
810 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
815 if (baseSettings
!= NULL
) CFRelease(baseSettings
);
816 if (wantSettings
!= NULL
) CFRelease(wantSettings
);
817 if (store
!= NULL
) CFRelease(store
);
826 #pragma mark Standalone test code
830 main(int argc
, char **argv
)
832 SCPreferencesRef prefs
;
835 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
837 prefs
= SCPreferencesCreate(NULL
, CFSTR("linkconfig"), NULL
);
841 set
= SCNetworkSetCopyCurrent(prefs
);
843 CFMutableSetRef seen
;
846 services
= SCNetworkSetCopyServices(set
);
847 if (services
!= NULL
) {
851 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
853 n
= CFArrayGetCount(services
);
854 for (i
= 0; i
< n
; i
++) {
855 SCNetworkInterfaceRef interface
;
856 SCNetworkServiceRef service
;
858 service
= CFArrayGetValueAtIndex(services
, i
);
859 interface
= SCNetworkServiceGetInterface(service
);
860 if ((interface
!= NULL
) &&
861 !CFSetContainsValue(seen
, interface
)) {
862 CFDictionaryRef capabilities
;
864 capabilities
= SCNetworkInterfaceCopyCapability(interface
, NULL
);
865 if (capabilities
!= NULL
) {
868 CFDictionaryRef options
;
870 options
= SCNetworkInterfaceGetConfiguration(interface
);
871 cap_current
= __SCNetworkInterfaceCreateCapabilities(interface
, -1, NULL
);
872 cap_requested
= __SCNetworkInterfaceCreateCapabilities(interface
, cap_current
, options
);
874 SCPrint(TRUE
, stdout
,
875 CFSTR("%sinterface = %@, current = %p, requested = %p\n%@\n"),
876 (i
== 0) ? "" : "\n",
877 SCNetworkInterfaceGetBSDName(interface
),
878 (void *)(uintptr_t)cap_current
,
879 (void *)(uintptr_t)cap_requested
,
881 CFRelease(capabilities
);
884 CFSetAddValue(seen
, interface
);
898 load_LinkConfiguration(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);