2 * Copyright (c) 2002-2007, 2011, 2013, 2015, 2016 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 #include "SCNetworkConfigurationInternal.h"
42 #include <SystemConfiguration/SCDPlugin.h> // for _SCDPluginExecCommand
45 static CFMutableDictionaryRef baseSettings
= NULL
;
46 static CFStringRef interfacesKey
= NULL
;
47 static SCDynamicStoreRef store
= NULL
;
48 static CFRunLoopSourceRef rls
= NULL
;
49 static CFMutableDictionaryRef wantSettings
= NULL
;
57 __log_LinkConfiguration()
59 static os_log_t log
= NULL
;
62 log
= os_log_create("com.apple.SystemConfiguration", "LinkConfiguration");
70 #pragma mark Capabilities
73 #define CAPABILITIES_KEY CFSTR("_CAPABILITIES_")
78 _SCNetworkInterfaceSetCapabilities(SCNetworkInterfaceRef interface
,
79 CFDictionaryRef options
)
81 CFDictionaryRef baseOptions
;
85 CFStringRef interfaceName
;
93 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
94 if (interfaceName
== NULL
) {
95 /* if no BSD interface name */
99 cap_current
= __SCNetworkInterfaceCreateCapabilities(interface
, -1, NULL
);
100 if (cap_current
== -1) {
101 /* could not get current capabilities */
105 // get base capabilities
106 cap_base
= cap_current
;
107 baseOptions
= CFDictionaryGetValue(baseSettings
, interfaceName
);
108 if (baseOptions
!= NULL
) {
111 num
= CFDictionaryGetValue(baseOptions
, CAPABILITIES_KEY
);
113 CFNumberGetValue(num
, kCFNumberIntType
, &cap_base
);
117 cap_requested
= __SCNetworkInterfaceCreateCapabilities(interface
, cap_base
, options
);
120 if (cap_requested
== cap_current
) {
121 /* if current setting is as requested */
125 bzero((char *)&ifr
, sizeof(ifr
));
126 (void)_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
127 ifr
.ifr_curcap
= cap_current
;
128 ifr
.ifr_reqcap
= cap_requested
;
130 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
132 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
136 ret
= ioctl(sock
, SIOCSIFCAP
, (caddr_t
)&ifr
);
139 SC_log(LOG_INFO
, "ioctl(SIOCSIFCAP) failed: %s", strerror(errno
));
149 #pragma mark Media options
152 static CFDictionaryRef
153 __copyMediaOptions(CFDictionaryRef options
)
155 CFMutableDictionaryRef requested
= NULL
;
158 if (!isA_CFDictionary(options
)) {
162 val
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaSubType
);
163 if (isA_CFString(val
)) {
164 requested
= CFDictionaryCreateMutable(NULL
,
166 &kCFTypeDictionaryKeyCallBacks
,
167 &kCFTypeDictionaryValueCallBacks
);
168 CFDictionaryAddValue(requested
, kSCPropNetEthernetMediaSubType
, val
);
174 val
= CFDictionaryGetValue(options
, kSCPropNetEthernetMediaOptions
);
175 if (isA_CFArray(val
)) {
176 CFDictionaryAddValue(requested
, kSCPropNetEthernetMediaOptions
, val
);
179 CFRelease(requested
);
189 _SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface
,
190 CFDictionaryRef options
)
192 CFArrayRef available
= NULL
;
193 CFDictionaryRef current
= NULL
;
194 struct ifmediareq ifm
;
196 CFStringRef interfaceName
;
199 CFDictionaryRef requested
;
202 if (!isA_SCNetworkInterface(interface
)) {
203 _SCErrorSet(kSCStatusInvalidArgument
);
207 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
208 if (interfaceName
== NULL
) {
209 /* if no BSD interface name */
210 SC_log(LOG_INFO
, "no BSD interface name for %@", interface
);
211 _SCErrorSet(kSCStatusInvalidArgument
);
215 /* get current & available options */
216 if (!SCNetworkInterfaceCopyMediaOptions(interface
, ¤t
, NULL
, &available
, FALSE
)) {
217 /* could not get current media options */
218 SC_log(LOG_INFO
, "no media options for %@", interfaceName
);
222 /* extract just the dictionary key/value pairs of interest */
223 requested
= __copyMediaOptions(options
);
224 if (requested
== NULL
) {
225 CFDictionaryRef baseOptions
;
227 /* get base options */
228 baseOptions
= CFDictionaryGetValue(baseSettings
, interfaceName
);
229 requested
= __copyMediaOptions(baseOptions
);
231 if (requested
== NULL
) {
232 /* get base options */
233 requested
= __copyMediaOptions(current
);
235 if (requested
== NULL
) {
236 /* if no media options to set */
240 if ((current
!= NULL
) && CFEqual(current
, requested
)) {
241 /* if current settings are as requested */
246 if (!CFArrayContainsValue(available
, CFRangeMake(0, CFArrayGetCount(available
)), requested
)) {
247 /* if requested settings not currently available */
248 SC_log(LOG_INFO
, "requested media settings unavailable for %@", interfaceName
);
252 newOptions
= __SCNetworkInterfaceCreateMediaOptions(interface
, requested
);
253 if (newOptions
== -1) {
254 /* since we have just validated, this should never happen */
258 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
260 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
264 bzero((char *)&ifm
, sizeof(ifm
));
265 (void)_SC_cfstring_to_cstring(interfaceName
, ifm
.ifm_name
, sizeof(ifm
.ifm_name
), kCFStringEncodingASCII
);
267 if (ioctl(sock
, SIOCGIFMEDIA
, (caddr_t
)&ifm
) == -1) {
268 SC_log(LOG_NOTICE
, "ioctl(SIOCGIFMEDIA) failed: %s", strerror(errno
));
272 bzero((char *)&ifr
, sizeof(ifr
));
273 bcopy(ifm
.ifm_name
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
));
274 ifr
.ifr_media
= ifm
.ifm_current
& ~(IFM_NMASK
|IFM_TMASK
|IFM_OMASK
|IFM_GMASK
);
275 ifr
.ifr_media
|= newOptions
;
277 SC_log(LOG_INFO
, "old media settings: 0x%8.8x (0x%8.8x)", ifm
.ifm_current
, ifm
.ifm_active
);
278 SC_log(LOG_INFO
, "new media settings: 0x%8.8x", ifr
.ifr_media
);
280 if (ioctl(sock
, SIOCSIFMEDIA
, (caddr_t
)&ifr
) == -1) {
281 SC_log(LOG_NOTICE
, "%@: ioctl(SIOCSIFMEDIA) failed: %s", interfaceName
, strerror(errno
));
289 if (available
!= NULL
) CFRelease(available
);
290 if (current
!= NULL
) CFRelease(current
);
291 if (requested
!= NULL
) CFRelease(requested
);
292 if (sock
!= -1) (void)close(sock
);
302 #ifndef USE_SIOCSIFMTU
304 ifconfig_exit(pid_t pid
, int status
, struct rusage
*rusage
, void *context
)
306 char *if_name
= (char *)context
;
308 if (WIFEXITED(status
)) {
309 if (WEXITSTATUS(status
) != 0) {
310 SC_log(LOG_NOTICE
, "ifconfig %s failed, exit status = %d",
312 WEXITSTATUS(status
));
314 } else if (WIFSIGNALED(status
)) {
315 SC_log(LOG_NOTICE
, "ifconfig %s: terminated w/signal = %d",
319 SC_log(LOG_NOTICE
, "ifconfig %s: exit status = %d",
324 CFAllocatorDeallocate(NULL
, if_name
);
327 #endif /* !USE_SIOCSIFMTU */
332 _SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface
,
333 CFDictionaryRef options
)
335 CFArrayRef bridge_members
= NULL
;
336 Boolean bridge_updated
= FALSE
;
337 CFStringRef interfaceName
;
338 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
339 CFStringRef interfaceType
;
347 interfaceName
= SCNetworkInterfaceGetBSDName(interface
);
348 if (interfaceName
== NULL
) {
349 /* if no BSD interface name */
353 if (!SCNetworkInterfaceCopyMTU(interface
, &mtu_cur
, &mtu_min
, &mtu_max
)) {
354 /* could not get current MTU */
359 if (isA_CFDictionary(options
)) {
360 val
= CFDictionaryGetValue(options
, kSCPropNetEthernetMTU
);
361 val
= isA_CFNumber(val
);
364 CFDictionaryRef baseOptions
;
367 baseOptions
= CFDictionaryGetValue(baseSettings
, interfaceName
);
368 if (baseOptions
!= NULL
) {
369 val
= CFDictionaryGetValue(baseOptions
, kSCPropNetEthernetMTU
);
373 CFNumberGetValue(val
, kCFNumberIntType
, &requested
);
378 if (requested
== mtu_cur
) {
379 /* if current setting is as requested */
383 if (((mtu_min
>= 0) && (requested
< mtu_min
)) ||
384 ((mtu_max
>= 0) && (requested
> mtu_max
))) {
385 /* if requested MTU outside of the valid range */
389 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
390 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypeBridge
)) {
391 bridge_members
= SCBridgeInterfaceGetMemberInterfaces(interface
);
392 if ((bridge_members
!= NULL
) && (CFArrayGetCount(bridge_members
) == 0)) {
394 bridge_members
= NULL
;
396 if (bridge_members
!= NULL
) {
397 SCNetworkInterfaceRef member0
;
399 /* temporarily, remove all bridge members */
400 CFRetain(bridge_members
);
401 ok
= SCBridgeInterfaceSetMemberInterfaces(interface
, NULL
);
406 /* and update the (bridge) configuration */
407 ok
= _SCBridgeInterfaceUpdateConfiguration(interfacePrivate
->prefs
);
412 /* switch from updating the MTU of the bridge to the first member */
413 member0
= CFArrayGetValueAtIndex(bridge_members
, 0);
414 interfaceName
= SCNetworkInterfaceGetBSDName(member0
);
416 bridge_updated
= TRUE
;
420 #ifdef USE_SIOCSIFMTU
426 bzero((char *)&ifr
, sizeof(ifr
));
427 (void)_SC_cfstring_to_cstring(interfaceName
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
), kCFStringEncodingASCII
);
428 ifr
.ifr_mtu
= requested
;
430 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
432 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
437 ret
= ioctl(sock
, SIOCSIFMTU
, (caddr_t
)&ifr
);
440 SC_log(LOG_NOTICE
, "ioctl(SIOCSIFMTU) failed: %s", strerror(errno
));
445 #else /* !USE_SIOCSIFMTU */
447 char *ifconfig_argv
[] = { "ifconfig", NULL
, "mtu", NULL
, NULL
};
450 ifconfig_argv
[1] = _SC_cfstring_to_cstring(interfaceName
, NULL
, 0, kCFStringEncodingASCII
);
451 (void)asprintf(&ifconfig_argv
[3], "%d", requested
);
453 pid
= _SCDPluginExecCommand(ifconfig_exit
, // callout,
454 ifconfig_argv
[1], // context
457 "/sbin/ifconfig", // path
458 ifconfig_argv
// argv
461 // CFAllocatorDeallocate(NULL, ifconfig_argv[1]); // released in ifconfig_exit()
462 free(ifconfig_argv
[3]);
469 #endif /* !USE_SIOCSIFMTU */
473 if (bridge_members
!= NULL
) {
474 /* restore bridge members */
475 (void) SCBridgeInterfaceSetMemberInterfaces(interface
, bridge_members
);
476 CFRelease(bridge_members
);
478 if (bridge_updated
) {
479 /* and update the (bridge) configuration */
480 (void) _SCBridgeInterfaceUpdateConfiguration(interfacePrivate
->prefs
);
489 #pragma mark Update link configuration
493 * Function: parse_component
495 * Given a string 'key' and a string prefix 'prefix',
496 * return the next component in the slash '/' separated
500 * 1. key = "a/b/c" prefix = "a/"
502 * 2. key = "a/b/c" prefix = "a/b/"
505 static CF_RETURNS_RETAINED CFStringRef
506 parse_component(CFStringRef key
, CFStringRef prefix
)
508 CFMutableStringRef comp
;
511 if (!CFStringHasPrefix(key
, prefix
)) {
514 comp
= CFStringCreateMutableCopy(NULL
, 0, key
);
515 CFStringDelete(comp
, CFRangeMake(0, CFStringGetLength(prefix
)));
516 range
= CFStringFind(comp
, CFSTR("/"), 0);
517 if (range
.location
== kCFNotFound
) {
520 range
.length
= CFStringGetLength(comp
) - range
.location
;
521 CFStringDelete(comp
, range
);
526 static void updateLink(CFStringRef interfaceName
, CFDictionaryRef options
);
530 updateInterfaces(CFArrayRef newInterfaces
)
535 static CFArrayRef oldInterfaces
= NULL
;
537 n_old
= (oldInterfaces
!= NULL
) ? CFArrayGetCount(oldInterfaces
) : 0;
538 n_new
= CFArrayGetCount(newInterfaces
);
540 for (i
= 0; i
< n_new
; i
++) {
541 CFStringRef interfaceName
;
543 interfaceName
= CFArrayGetValueAtIndex(newInterfaces
, i
);
546 !CFArrayContainsValue(oldInterfaces
,
547 CFRangeMake(0, n_old
),
549 CFDictionaryRef options
;
552 options
= CFDictionaryGetValue(wantSettings
, interfaceName
);
553 updateLink(interfaceName
, options
);
557 if (oldInterfaces
!= NULL
) CFRelease(oldInterfaces
);
558 oldInterfaces
= CFRetain(newInterfaces
);
563 updateLink(CFStringRef interfaceName
, CFDictionaryRef options
)
565 SCNetworkInterfaceRef interface
;
567 /* retain requested configuration */
568 if (options
!= NULL
) {
569 CFDictionarySetValue(wantSettings
, interfaceName
, options
);
571 CFDictionaryRemoveValue(wantSettings
, interfaceName
);
574 /* apply requested configuration */
575 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, interfaceName
,
576 kIncludeAllVirtualInterfaces
);
577 if (interface
== NULL
) {
581 if (options
!= NULL
) {
582 if (!CFDictionaryContainsKey(baseSettings
, interfaceName
)) {
584 CFDictionaryRef cur_media
= NULL
;
585 CFMutableDictionaryRef new_media
= NULL
;
588 /* preserve current media options */
589 if (SCNetworkInterfaceCopyMediaOptions(interface
, &cur_media
, NULL
, NULL
, FALSE
)) {
590 if (cur_media
!= NULL
) {
591 new_media
= CFDictionaryCreateMutableCopy(NULL
, 0, cur_media
);
592 CFRelease(cur_media
);
596 /* preserve current MTU */
597 if (SCNetworkInterfaceCopyMTU(interface
, &cur_mtu
, NULL
, NULL
)) {
601 if (new_media
== NULL
) {
602 new_media
= CFDictionaryCreateMutable(NULL
,
604 &kCFTypeDictionaryKeyCallBacks
,
605 &kCFTypeDictionaryValueCallBacks
);
608 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &cur_mtu
);
609 CFDictionaryAddValue(new_media
, kSCPropNetEthernetMTU
, num
);
614 /* preserve capabilities */
615 cur_cap
= __SCNetworkInterfaceCreateCapabilities(interface
, -1, NULL
);
619 if (new_media
== NULL
) {
620 new_media
= CFDictionaryCreateMutable(NULL
,
622 &kCFTypeDictionaryKeyCallBacks
,
623 &kCFTypeDictionaryValueCallBacks
);
626 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &cur_cap
);
627 CFDictionaryAddValue(new_media
, CAPABILITIES_KEY
, num
);
631 if (new_media
!= NULL
) {
632 CFDictionarySetValue(baseSettings
, interfaceName
, new_media
);
633 CFRelease(new_media
);
637 /* establish new settings */
638 (void)_SCNetworkInterfaceSetCapabilities(interface
, options
);
639 (void)_SCNetworkInterfaceSetMediaOptions(interface
, options
);
640 (void)_SCNetworkInterfaceSetMTU (interface
, options
);
642 /* no requested settings */
643 options
= CFDictionaryGetValue(baseSettings
, interfaceName
);
644 if (options
!= NULL
) {
645 /* restore original settings */
646 (void)_SCNetworkInterfaceSetCapabilities(interface
, options
);
647 (void)_SCNetworkInterfaceSetMediaOptions(interface
, options
);
648 (void)_SCNetworkInterfaceSetMTU (interface
, options
);
649 CFDictionaryRemoveValue(baseSettings
, interfaceName
);
653 CFRelease(interface
);
659 linkConfigChangedCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *arg
)
661 os_activity_t activity
;
662 CFDictionaryRef changes
;
665 static CFStringRef prefix
= NULL
;
667 activity
= os_activity_create("processing link configuration changes",
669 OS_ACTIVITY_FLAG_DEFAULT
);
670 os_activity_scope(activity
);
672 if (prefix
== NULL
) {
673 prefix
= SCDynamicStoreKeyCreate(NULL
,
675 kSCDynamicStoreDomainSetup
,
680 changes
= SCDynamicStoreCopyMultiple(store
, changedKeys
, NULL
);
682 n
= (changes
!= NULL
) ? CFArrayGetCount(changedKeys
) : 0;
683 for (i
= 0; i
< n
; i
++) {
685 CFDictionaryRef info
;
687 key
= CFArrayGetValueAtIndex(changedKeys
, i
);
688 info
= CFDictionaryGetValue(changes
, key
);
690 if (CFEqual(key
, interfacesKey
)) {
691 if (isA_CFDictionary(info
) != NULL
) {
692 CFArrayRef interfaces
;
694 interfaces
= CFDictionaryGetValue(info
, kSCPropNetInterfaces
);
695 if (isA_CFArray(interfaces
)) {
696 updateInterfaces(interfaces
);
700 CFStringRef interfaceName
;
702 interfaceName
= parse_component(key
, prefix
);
703 if (interfaceName
!= NULL
) {
704 updateLink(interfaceName
, info
);
705 CFRelease(interfaceName
);
710 if (changes
!= NULL
) {
714 os_release(activity
);
722 load_LinkConfiguration(CFBundleRef bundle
, Boolean bundleVerbose
)
725 CFMutableArrayRef keys
= NULL
;
727 CFMutableArrayRef patterns
= NULL
;
729 SC_log(LOG_DEBUG
, "load() called");
730 SC_log(LOG_DEBUG
, " bundle ID = %@", CFBundleGetIdentifier(bundle
));
732 /* initialize a few globals */
734 baseSettings
= CFDictionaryCreateMutable(NULL
,
736 &kCFTypeDictionaryKeyCallBacks
,
737 &kCFTypeDictionaryValueCallBacks
);
738 wantSettings
= CFDictionaryCreateMutable(NULL
,
740 &kCFTypeDictionaryKeyCallBacks
,
741 &kCFTypeDictionaryValueCallBacks
);
743 /* open a "configd" store to allow cache updates */
744 store
= SCDynamicStoreCreate(NULL
,
745 CFSTR("Link Configuraton plug-in"),
746 linkConfigChangedCallback
,
749 SC_log(LOG_ERR
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
753 /* establish notification keys and patterns */
754 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
755 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
757 /* ...watch for a change in the list of network interfaces */
758 interfacesKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
759 kSCDynamicStoreDomainState
);
760 CFArrayAppendValue(keys
, interfacesKey
);
762 /* ...watch for (per-interface) AirPort configuration changes */
763 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
764 kSCDynamicStoreDomainSetup
,
767 CFArrayAppendValue(patterns
, key
);
770 /* ...watch for (per-interface) Ethernet configuration changes */
771 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
772 kSCDynamicStoreDomainSetup
,
775 CFArrayAppendValue(patterns
, key
);
778 /* ...watch for (per-interface) FireWire configuration changes */
779 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
780 kSCDynamicStoreDomainSetup
,
783 CFArrayAppendValue(patterns
, key
);
786 /* register the keys/patterns */
787 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
);
791 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed: %s",
792 SCErrorString(SCError()));
796 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
798 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed: %s",
799 SCErrorString(SCError()));
803 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
808 if (baseSettings
!= NULL
) CFRelease(baseSettings
);
809 if (wantSettings
!= NULL
) CFRelease(wantSettings
);
810 if (store
!= NULL
) CFRelease(store
);
819 #pragma mark Standalone test code
823 main(int argc
, char **argv
)
825 SCPreferencesRef prefs
;
828 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
830 prefs
= SCPreferencesCreate(NULL
, CFSTR("linkconfig"), NULL
);
834 set
= SCNetworkSetCopyCurrent(prefs
);
836 CFMutableSetRef seen
;
839 services
= SCNetworkSetCopyServices(set
);
840 if (services
!= NULL
) {
844 seen
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
846 n
= CFArrayGetCount(services
);
847 for (i
= 0; i
< n
; i
++) {
848 SCNetworkInterfaceRef interface
;
849 SCNetworkServiceRef service
;
851 service
= CFArrayGetValueAtIndex(services
, i
);
852 interface
= SCNetworkServiceGetInterface(service
);
853 if ((interface
!= NULL
) &&
854 !CFSetContainsValue(seen
, interface
)) {
855 CFDictionaryRef capabilities
;
857 capabilities
= SCNetworkInterfaceCopyCapability(interface
, NULL
);
858 if (capabilities
!= NULL
) {
861 CFDictionaryRef options
;
863 options
= SCNetworkInterfaceGetConfiguration(interface
);
864 cap_current
= __SCNetworkInterfaceCreateCapabilities(interface
, -1, NULL
);
865 cap_requested
= __SCNetworkInterfaceCreateCapabilities(interface
, cap_current
, options
);
867 SCPrint(TRUE
, stdout
,
868 CFSTR("%sinterface = %@, current = %p, requested = %p\n%@\n"),
869 (i
== 0) ? "" : "\n",
870 SCNetworkInterfaceGetBSDName(interface
),
871 (void *)(uintptr_t)cap_current
,
872 (void *)(uintptr_t)cap_requested
,
874 CFRelease(capabilities
);
877 CFSetAddValue(seen
, interface
);
891 load_LinkConfiguration(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);