2 * Copyright (c) 2009-2013 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 * July 27, 2009 Allan Nathanson <ajn@apple.com>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include "SCNetworkConfigurationInternal.h"
37 #include <SystemConfiguration/SCValidation.h>
38 #include <SystemConfiguration/SCPrivate.h>
43 #include <sys/types.h>
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <net/ethernet.h>
48 #define KERNEL_PRIVATE
50 #include <net/if_var.h>
52 #include <net/if_types.h>
53 #include <net/if_media.h>
54 #include <net/route.h>
57 #include <net/if_bridgevar.h>
60 /* ---------- Bridge support ---------- */
67 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
69 SCLog(TRUE
, LOG_ERR
, CFSTR("socket() failed: %s"), strerror(errno
));
76 static struct ifbifconf
*
77 ifbifconf_copy(int s
, const char * ifname
)
81 struct ifbifconf
* ibc_p
= NULL
;
83 uint32_t len
= sizeof(struct ifbreq
) * 16;
85 bzero(&ifd
, sizeof(ifd
));
86 strncpy(ifd
.ifd_name
, ifname
, sizeof(ifd
.ifd_name
));
87 ifd
.ifd_cmd
= BRDGGIFS
;
89 buflen
= sizeof(struct ifbifconf
) + len
;
93 ibc_p
= (struct ifbifconf
*)buf
;
94 ibc_p
->ifbic_len
= len
;
95 ibc_p
->ifbic_buf
= buf
+ sizeof(*ibc_p
);
97 ifd
.ifd_len
= sizeof(*ibc_p
);
99 if (ioctl(s
, SIOCGDRVSPEC
, (caddr_t
)&ifd
) == -1) {
103 if ((ibc_p
->ifbic_len
+ sizeof(struct ifbreq
)) < len
) {
104 // if we have room for all of the member interfaces
109 buflen
= sizeof(struct ifbifconf
) + len
;
110 buf
= reallocf(buf
, buflen
);
129 add_interface(CFMutableArrayRef
*interfaces
, CFStringRef if_name
)
131 SCNetworkInterfaceRef interface
;
133 if (*interfaces
== NULL
) {
134 *interfaces
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
137 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, if_name
,
138 kIncludeNoVirtualInterfaces
);
139 CFArrayAppendValue(*interfaces
, interface
);
140 CFRelease(interface
);
145 _SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge
, CFArrayRef members
);
149 CFMutableArrayRef bridges
;
150 SCPreferencesRef prefs
;
151 } addContext
, *addContextRef
;
155 add_configured_interface(const void *key
, const void *value
, void *context
)
157 SCBridgeInterfaceRef bridge
;
158 CFStringRef bridge_if
= (CFStringRef
)key
;
159 CFDictionaryRef bridge_info
= (CFDictionaryRef
)value
;
160 CFDictionaryRef bridge_options
;
162 CFArrayRef interfaces
;
163 SCNetworkInterfacePrivateRef interfacePrivate
;
164 CFMutableArrayRef members
= NULL
;
165 addContextRef myContext
= (addContextRef
)context
;
167 CFStringRef name_auto
= NULL
;
170 // create the bridge interface
171 bridge
= (SCBridgeInterfaceRef
)_SCBridgeInterfaceCreatePrivate(NULL
, bridge_if
);
172 assert(bridge
!= NULL
);
174 // estabish link to the stored configuration
175 interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
176 interfacePrivate
->prefs
= CFRetain(myContext
->prefs
);
178 // add member interfaces
179 interfaces
= CFDictionaryGetValue(bridge_info
, kSCPropVirtualNetworkInterfacesBridgeInterfaces
);
180 n
= isA_CFArray(interfaces
) ? CFArrayGetCount(interfaces
) : 0;
181 for (i
= 0; i
< n
; i
++) {
184 member
= CFArrayGetValueAtIndex(interfaces
, i
);
185 if (isA_CFString(member
)) {
186 add_interface(&members
, member
);
189 if (members
!= NULL
) {
190 _SCBridgeInterfaceSetMemberInterfaces(bridge
, members
);
195 bridge_options
= CFDictionaryGetValue(bridge_info
, kSCPropVirtualNetworkInterfacesBridgeOptions
);
196 if (isA_CFDictionary(bridge_options
)) {
197 SCBridgeInterfaceSetOptions(bridge
, bridge_options
);
198 name_auto
= CFDictionaryGetValue(bridge_options
, CFSTR("__AUTO__"));
202 name
= CFDictionaryGetValue(bridge_info
, kSCPropUserDefinedName
);
203 if (isA_CFString(name
)) {
204 SCBridgeInterfaceSetLocalizedDisplayName(bridge
, name
);
205 } else if (isA_CFString(name_auto
)) {
206 interfacePrivate
->localized_key
= name_auto
;
207 if (interfacePrivate
->localized_arg1
!= NULL
) {
208 CFRelease(interfacePrivate
->localized_arg1
);
209 interfacePrivate
->localized_arg1
= NULL
;
213 CFArrayAppendValue(myContext
->bridges
, bridge
);
221 #pragma mark SCBridgeInterface APIs
224 static __inline__
void
225 my_CFDictionaryApplyFunction(CFDictionaryRef theDict
,
226 CFDictionaryApplierFunction applier
,
229 CFAllocatorRef myAllocator
;
230 CFDictionaryRef myDict
;
232 myAllocator
= CFGetAllocator(theDict
);
233 myDict
= CFDictionaryCreateCopy(myAllocator
, theDict
);
234 CFDictionaryApplyFunction(myDict
, applier
, context
);
241 SCBridgeInterfaceCopyAll(SCPreferencesRef prefs
)
244 CFDictionaryRef dict
;
247 context
.bridges
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
248 context
.prefs
= prefs
;
250 path
= CFStringCreateWithFormat(NULL
,
253 kSCPrefVirtualNetworkInterfaces
,
254 kSCNetworkInterfaceTypeBridge
);
255 dict
= SCPreferencesPathGetValue(prefs
, path
);
256 if (isA_CFDictionary(dict
)) {
257 my_CFDictionaryApplyFunction(dict
, add_configured_interface
, &context
);
261 return context
.bridges
;
265 __private_extern__
void
266 __SCBridgeInterfaceListCollectMembers(CFArrayRef interfaces
, CFMutableSetRef set
)
271 n
= CFArrayGetCount(interfaces
);
272 for (i
= 0; i
< n
; i
++) {
273 SCBridgeInterfaceRef bridgeInterface
;
276 bridgeInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
277 members
= SCBridgeInterfaceGetMemberInterfaces(bridgeInterface
);
278 if (members
!= NULL
) {
282 // exclude the member interfaces of this bridge
283 n_members
= CFArrayGetCount(members
);
284 for (j
= 0; j
< n_members
; j
++) {
285 SCNetworkInterfaceRef member
;
287 member
= CFArrayGetValueAtIndex(members
, j
);
288 CFSetAddValue(set
, member
);
297 CFArrayRef
/* of SCNetworkInterfaceRef's */
298 SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs
)
300 CFMutableArrayRef available
;
301 CFMutableSetRef excluded
;
302 CFArrayRef interfaces
;
304 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
305 excluded
= CFSetCreateMutable (NULL
, 0, &kCFTypeSetCallBacks
);
307 #if !TARGET_OS_IPHONE
308 // exclude Bond [member] interfaces
309 interfaces
= SCBondInterfaceCopyAll(prefs
);
310 if (interfaces
!= NULL
) {
311 __SCBondInterfaceListCollectMembers(interfaces
, excluded
);
312 CFRelease(interfaces
);
314 #endif // !TARGET_OS_IPHONE
316 // exclude Bridge [member] interfaces
317 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
318 if (interfaces
!= NULL
) {
319 __SCBridgeInterfaceListCollectMembers(interfaces
, excluded
);
320 CFRelease(interfaces
);
323 // exclude VLAN [physical] interfaces
324 interfaces
= SCVLANInterfaceCopyAll(prefs
);
325 if (interfaces
!= NULL
) {
329 n
= CFArrayGetCount(interfaces
);
330 for (i
= 0; i
< n
; i
++) {
331 SCVLANInterfaceRef vlanInterface
;
332 SCNetworkInterfaceRef physical
;
334 // exclude the physical interface of this VLAN
335 vlanInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
336 physical
= SCVLANInterfaceGetPhysicalInterface(vlanInterface
);
337 CFSetAddValue(excluded
, physical
);
339 CFRelease(interfaces
);
342 // identify available interfaces
343 interfaces
= __SCNetworkInterfaceCopyAll_IONetworkInterface();
344 if (interfaces
!= NULL
) {
348 n
= CFArrayGetCount(interfaces
);
349 for (i
= 0; i
< n
; i
++) {
350 SCNetworkInterfaceRef interface
;
351 SCNetworkInterfacePrivateRef interfacePrivate
;
353 interface
= CFArrayGetValueAtIndex(interfaces
, i
);
354 interfacePrivate
= (SCNetworkInterfacePrivateRef
)interface
;
356 if (!interfacePrivate
->supportsBridge
) {
357 // if this interface is not available
361 if (CFSetContainsValue(excluded
, interface
)) {
366 CFArrayAppendValue(available
, interface
);
368 CFRelease(interfaces
);
378 _SCBridgeInterfaceCopyActive(void)
380 struct ifaddrs
*ifap
;
383 CFMutableArrayRef bridges
= NULL
;
385 if (getifaddrs(&ifap
) == -1) {
387 SCLog(TRUE
, LOG_ERR
, CFSTR("getifaddrs() failed: %s"), strerror(errno
));
391 s
= inet_dgram_socket();
397 bridges
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
399 for (ifp
= ifap
; ifp
!= NULL
; ifp
= ifp
->ifa_next
) {
401 SCBridgeInterfaceRef bridge
;
402 CFStringRef bridge_if
;
403 struct ifbifconf
*ibc_p
;
404 struct if_data
*if_data
;
405 CFMutableArrayRef members
= NULL
;
408 if_data
= (struct if_data
*)ifp
->ifa_data
;
410 || ifp
->ifa_addr
->sa_family
!= AF_LINK
411 || if_data
->ifi_type
!= IFT_BRIDGE
) {
415 // check the interface name ("bridgeNNN") and ensure that
416 // we leave all non-SC configured bridge interfaces (those
417 // with unit #'s >= 100) alone.
418 n
= strlen(ifp
->ifa_name
);
420 isdigit(ifp
->ifa_name
[n
- 1]) &&
421 isdigit(ifp
->ifa_name
[n
- 2]) &&
422 isdigit(ifp
->ifa_name
[n
- 3])) {
423 // if not SC managed bridge interface
427 ibc_p
= ifbifconf_copy(s
, ifp
->ifa_name
);
429 if (errno
== EBUSY
) {
434 CFSTR("ifbifconf_copy(%s) failed: %s"),
442 // create the bridge interface
443 bridge_if
= CFStringCreateWithCString(NULL
, ifp
->ifa_name
, kCFStringEncodingASCII
);
444 bridge
= (SCBridgeInterfaceRef
)_SCBridgeInterfaceCreatePrivate(NULL
, bridge_if
);
445 CFRelease(bridge_if
);
447 // add member interfaces
448 if (ibc_p
->ifbic_len
> 0) {
451 // iterate over each member interface
452 for (i
= 0; i
< ibc_p
->ifbic_len
/ sizeof(struct ifbreq
); i
++) {
453 struct ifbreq
*ibr_p
;
456 ibr_p
= ibc_p
->ifbic_req
+ i
;
457 member
= CFStringCreateWithCString(NULL
, ibr_p
->ifbr_ifsname
, kCFStringEncodingASCII
);
458 add_interface(&members
, member
);
464 if (members
!= NULL
) {
465 _SCBridgeInterfaceSetMemberInterfaces(bridge
, members
);
470 CFArrayAppendValue(bridges
, bridge
);
486 SCBridgeInterfaceCreate(SCPreferencesRef prefs
)
488 CFAllocatorRef allocator
;
489 SCBridgeInterfaceRef bridge
= NULL
;
493 _SCErrorSet(kSCStatusInvalidArgument
);
497 allocator
= CFGetAllocator(prefs
);
499 // create a new bridge using an unused interface name
500 for (i
= 0; bridge
== NULL
; i
++) {
501 CFDictionaryRef dict
;
502 CFStringRef bridge_if
;
503 SCNetworkInterfacePrivateRef interfacePrivate
;
504 CFMutableDictionaryRef newDict
;
505 CFArrayRef newInterfaces
;
509 bridge_if
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("bridge%ld"), i
);
510 path
= CFStringCreateWithFormat(allocator
,
513 kSCPrefVirtualNetworkInterfaces
,
514 kSCNetworkInterfaceTypeBridge
,
516 dict
= SCPreferencesPathGetValue(prefs
, path
);
518 // if bridge interface name not available
520 CFRelease(bridge_if
);
524 // add the bridge to the stored preferences
525 newDict
= CFDictionaryCreateMutable(allocator
,
527 &kCFTypeDictionaryKeyCallBacks
,
528 &kCFTypeDictionaryValueCallBacks
);
529 newInterfaces
= CFArrayCreate(allocator
, NULL
, 0, &kCFTypeArrayCallBacks
);
530 CFDictionaryAddValue(newDict
, kSCPropVirtualNetworkInterfacesBridgeInterfaces
, newInterfaces
);
531 CFRelease(newInterfaces
);
532 ok
= SCPreferencesPathSetValue(prefs
, path
, newDict
);
536 // if the bridge could not be saved
537 CFRelease(bridge_if
);
541 // create the SCBridgeInterfaceRef
542 bridge
= (SCBridgeInterfaceRef
)_SCBridgeInterfaceCreatePrivate(allocator
, bridge_if
);
543 CFRelease(bridge_if
);
545 // estabish link to the stored configuration
546 interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
547 interfacePrivate
->prefs
= CFRetain(prefs
);
555 SCBridgeInterfaceRemove(SCBridgeInterfaceRef bridge
)
557 CFStringRef bridge_if
;
558 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
562 if (!isA_SCBridgeInterface(bridge
)) {
563 _SCErrorSet(kSCStatusInvalidArgument
);
567 if (interfacePrivate
->prefs
== NULL
) {
568 _SCErrorSet(kSCStatusInvalidArgument
);
572 bridge_if
= SCNetworkInterfaceGetBSDName(bridge
);
573 path
= CFStringCreateWithFormat(NULL
,
576 kSCPrefVirtualNetworkInterfaces
,
577 kSCNetworkInterfaceTypeBridge
,
579 ok
= SCPreferencesPathRemoveValue(interfacePrivate
->prefs
, path
);
587 SCBridgeInterfaceGetMemberInterfaces(SCBridgeInterfaceRef bridge
)
589 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
591 if (!isA_SCBridgeInterface(bridge
)) {
592 _SCErrorSet(kSCStatusInvalidArgument
);
596 return interfacePrivate
->bridge
.interfaces
;
601 SCBridgeInterfaceGetOptions(SCBridgeInterfaceRef bridge
)
603 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
605 if (!isA_SCBridgeInterface(bridge
)) {
606 _SCErrorSet(kSCStatusInvalidArgument
);
610 return interfacePrivate
->bridge
.options
;
615 _SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge
, CFArrayRef members
)
618 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
620 CFMutableArrayRef newMembers
;
623 n
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
625 // set member interfaces in the stored preferences
626 if (interfacePrivate
->prefs
!= NULL
) {
627 CFDictionaryRef dict
;
628 CFMutableDictionaryRef newDict
;
631 path
= CFStringCreateWithFormat(NULL
,
634 kSCPrefVirtualNetworkInterfaces
,
635 kSCNetworkInterfaceTypeBridge
,
636 interfacePrivate
->entity_device
);
637 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
638 if (!isA_CFDictionary(dict
)) {
639 // if the prefs are confused
641 _SCErrorSet(kSCStatusFailed
);
645 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
646 for (i
= 0; i
< n
; i
++) {
647 SCNetworkInterfaceRef interface
;
648 CFStringRef memberName
;
650 interface
= CFArrayGetValueAtIndex(members
, i
);
651 memberName
= SCNetworkInterfaceGetBSDName(interface
);
652 CFArrayAppendValue(newMembers
, memberName
);
655 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
656 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesBridgeInterfaces
, newMembers
);
657 CFRelease(newMembers
);
658 if (!CFEqual(dict
, newDict
)) {
659 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
666 newMembers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
667 for (i
= 0; i
< n
; i
++) {
668 SCNetworkInterfaceRef member
;
669 SCNetworkInterfacePrivateRef newMember
;
671 member
= CFArrayGetValueAtIndex(members
, i
);
672 newMember
= __SCNetworkInterfaceCreateCopy(NULL
,
674 interfacePrivate
->prefs
,
675 interfacePrivate
->serviceID
);
676 CFArrayAppendValue(newMembers
, newMember
);
677 CFRelease(newMember
);
679 CFRelease(interfacePrivate
->bridge
.interfaces
);
680 interfacePrivate
->bridge
.interfaces
= newMembers
;
688 SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge
, CFArrayRef members
)
690 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
692 int sc_status
= kSCStatusOK
;
694 if (!isA_SCBridgeInterface(bridge
)) {
695 _SCErrorSet(kSCStatusInvalidArgument
);
699 if ((members
!= NULL
) && !isA_CFArray(members
)) {
700 _SCErrorSet(kSCStatusInvalidArgument
);
704 if (interfacePrivate
->prefs
!= NULL
) {
705 CFArrayRef available
;
711 CFArrayRef services
= NULL
;
713 current
= SCBridgeInterfaceGetMemberInterfaces(bridge
);
714 n_current
= (current
!= NULL
) ? CFArrayGetCount(current
) : 0;
716 available
= SCBridgeInterfaceCopyAvailableMemberInterfaces(interfacePrivate
->prefs
);
717 n_available
= (available
!= NULL
) ? CFArrayGetCount(available
) : 0;
719 n_members
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
720 for (i
= 0; i
< n_members
; i
++) {
721 SCNetworkInterfaceRef member
;
723 member
= CFArrayGetValueAtIndex(members
, i
);
725 if ((current
!= NULL
) &&
726 CFArrayContainsValue(current
, CFRangeMake(0, n_current
), member
)) {
727 // current members are allowed
731 if ((available
!= NULL
) &&
732 CFArrayContainsValue(available
, CFRangeMake(0, n_available
), member
)) {
733 // available members are allowed but cannot be associated
734 // with any other network services.
736 if (services
== NULL
) {
737 services
= __SCNetworkServiceCopyAllEnabled(interfacePrivate
->prefs
);
739 if ((services
!= NULL
) &&
740 __SCNetworkServiceExistsForInterface(services
, member
)) {
741 sc_status
= kSCStatusKeyExists
;
749 // if member not allowed
750 sc_status
= kSCStatusInvalidArgument
;
754 if (available
!= NULL
) CFRelease(available
);
755 if (services
!= NULL
) CFRelease(services
);
758 if (sc_status
!= kSCStatusOK
) {
759 _SCErrorSet(sc_status
);
763 ok
= _SCBridgeInterfaceSetMemberInterfaces(bridge
, members
);
769 SCBridgeInterfaceSetLocalizedDisplayName(SCBridgeInterfaceRef bridge
, CFStringRef newName
)
771 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
774 if (!isA_SCBridgeInterface(bridge
)) {
775 _SCErrorSet(kSCStatusInvalidArgument
);
779 if ((newName
!= NULL
) && !isA_CFString(newName
)) {
780 _SCErrorSet(kSCStatusInvalidArgument
);
784 // set name in the stored preferences
785 if (interfacePrivate
->prefs
!= NULL
) {
786 CFDictionaryRef dict
;
787 CFMutableDictionaryRef newDict
;
790 path
= CFStringCreateWithFormat(NULL
,
793 kSCPrefVirtualNetworkInterfaces
,
794 kSCNetworkInterfaceTypeBridge
,
795 interfacePrivate
->entity_device
);
796 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
797 if (!isA_CFDictionary(dict
)) {
798 // if the prefs are confused
800 _SCErrorSet(kSCStatusFailed
);
804 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
805 if (newName
!= NULL
) {
806 CFDictionarySetValue(newDict
, kSCPropUserDefinedName
, newName
);
808 CFDictionaryRemoveValue(newDict
, kSCPropUserDefinedName
);
810 if (!CFEqual(dict
, newDict
)) {
811 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
817 // set name in the SCBridgeInterfaceRef
819 if (interfacePrivate
->localized_name
!= NULL
) {
820 CFRelease(interfacePrivate
->localized_name
);
821 interfacePrivate
->localized_name
= NULL
;
823 if (newName
!= NULL
) {
824 interfacePrivate
->localized_name
= CFStringCreateCopy(NULL
, newName
);
833 SCBridgeInterfaceSetOptions(SCBridgeInterfaceRef bridge
, CFDictionaryRef newOptions
)
835 SCNetworkInterfacePrivateRef interfacePrivate
= (SCNetworkInterfacePrivateRef
)bridge
;
838 if (!isA_SCBridgeInterface(bridge
)) {
839 _SCErrorSet(kSCStatusInvalidArgument
);
843 if ((newOptions
!= NULL
) && !isA_CFDictionary(newOptions
)) {
844 _SCErrorSet(kSCStatusInvalidArgument
);
848 // set options in the stored preferences
849 if (interfacePrivate
->prefs
!= NULL
) {
850 CFDictionaryRef dict
;
851 CFMutableDictionaryRef newDict
;
854 path
= CFStringCreateWithFormat(NULL
,
857 kSCPrefVirtualNetworkInterfaces
,
858 kSCNetworkInterfaceTypeBridge
,
859 interfacePrivate
->entity_device
);
860 dict
= SCPreferencesPathGetValue(interfacePrivate
->prefs
, path
);
861 if (!isA_CFDictionary(dict
)) {
862 // if the prefs are confused
864 _SCErrorSet(kSCStatusFailed
);
868 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
869 if (newOptions
!= NULL
) {
870 CFDictionarySetValue(newDict
, kSCPropVirtualNetworkInterfacesBridgeOptions
, newOptions
);
872 CFDictionaryRemoveValue(newDict
, kSCPropVirtualNetworkInterfacesBridgeOptions
);
874 if (!CFEqual(dict
, newDict
)) {
875 ok
= SCPreferencesPathSetValue(interfacePrivate
->prefs
, path
, newDict
);
881 // set options in the SCBridgeInterfaceRef
883 if (interfacePrivate
->bridge
.options
!= NULL
) {
884 CFRelease(interfacePrivate
->bridge
.options
);
885 interfacePrivate
->bridge
.options
= NULL
;
887 if (newOptions
!= NULL
) {
888 CFStringRef name_auto
= NULL
;
890 interfacePrivate
->bridge
.options
= CFDictionaryCreateCopy(NULL
, newOptions
);
892 // set [auto] display name from options
893 if ((interfacePrivate
->localized_name
== NULL
) &&
894 CFDictionaryGetValueIfPresent(newOptions
,
896 (const void **)&name_auto
) &&
897 isA_CFString(name_auto
)) {
899 interfacePrivate
->localized_key
= name_auto
;
900 if (interfacePrivate
->localized_arg1
!= NULL
) {
901 CFRelease(interfacePrivate
->localized_arg1
);
902 interfacePrivate
->localized_arg1
= NULL
;
913 #pragma mark SCBridgeInterface management
918 __bridge_add_interface(int s
, CFStringRef bridge_if
, CFStringRef interface_if
)
924 bzero(&ifd
, sizeof(ifd
));
925 (void) _SC_cfstring_to_cstring(bridge_if
,
927 sizeof(ifd
.ifd_name
),
928 kCFStringEncodingASCII
);
929 ifd
.ifd_cmd
= BRDGADD
;
930 ifd
.ifd_len
= sizeof(breq
);
931 ifd
.ifd_data
= (caddr_t
)&breq
;
934 bzero(&breq
, sizeof(breq
));
935 (void) _SC_cfstring_to_cstring(interface_if
,
937 sizeof(breq
.ifbr_ifsname
),
938 kCFStringEncodingASCII
);
940 // add new bridge member
941 if (ioctl(s
, SIOCSDRVSPEC
, (caddr_t
)&ifd
) == -1) {
944 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"),
956 __bridge_remove_interface(int s
, CFStringRef bridge_if
, CFStringRef interface_if
)
962 bzero(&ifd
, sizeof(ifd
));
963 (void) _SC_cfstring_to_cstring(bridge_if
,
965 sizeof(ifd
.ifd_name
),
966 kCFStringEncodingASCII
);
967 ifd
.ifd_cmd
= BRDGDEL
;
968 ifd
.ifd_len
= sizeof(breq
);
969 ifd
.ifd_data
= (caddr_t
)&breq
;
971 // bridge member to remove
972 bzero(&breq
, sizeof(breq
));
973 (void) _SC_cfstring_to_cstring(interface_if
,
975 sizeof(breq
.ifbr_ifsname
),
976 kCFStringEncodingASCII
);
978 // remove bridge member
979 if (ioctl(s
, SIOCSDRVSPEC
, (caddr_t
)&ifd
) == -1) {
982 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"),
995 _SCBridgeInterfaceUpdateConfiguration(SCPreferencesRef prefs
)
998 CFArrayRef active
= NULL
;
999 CFArrayRef config
= NULL
;
1006 if (prefs
== NULL
) {
1007 _SCErrorSet(kSCStatusInvalidArgument
);
1011 /* configured Bridges */
1012 config
= SCBridgeInterfaceCopyAll(prefs
);
1013 nConfig
= (config
!= NULL
) ? CFArrayGetCount(config
) : 0;
1015 /* active Bridges */
1016 active
= _SCBridgeInterfaceCopyActive();
1017 nActive
= (active
!= NULL
) ? CFArrayGetCount(active
) : 0;
1020 * remove any no-longer-configured bridge interfaces and
1021 * any devices associated with a bridge that are no longer
1022 * associated with a bridge.
1024 for (i
= 0; i
< nActive
; i
++) {
1025 SCBridgeInterfaceRef a_bridge
;
1026 CFStringRef a_bridge_if
;
1028 Boolean found
= FALSE
;
1030 a_bridge
= CFArrayGetValueAtIndex(active
, i
);
1031 a_bridge_if
= SCNetworkInterfaceGetBSDName(a_bridge
);
1033 for (j
= 0; j
< nConfig
; j
++) {
1034 SCBridgeInterfaceRef c_bridge
;
1035 CFStringRef c_bridge_if
;
1037 c_bridge
= CFArrayGetValueAtIndex(config
, j
);
1038 c_bridge_if
= SCNetworkInterfaceGetBSDName(c_bridge
);
1040 if (CFEqual(a_bridge_if
, c_bridge_if
)) {
1042 CFArrayRef a_bridge_interfaces
;
1044 CFArrayRef c_bridge_interfaces
;
1047 c_bridge_interfaces
= SCBridgeInterfaceGetMemberInterfaces(c_bridge
);
1048 c_count
= (c_bridge_interfaces
!= NULL
) ? CFArrayGetCount(c_bridge_interfaces
) : 0;
1050 a_bridge_interfaces
= SCBridgeInterfaceGetMemberInterfaces(a_bridge
);
1051 a_count
= (a_bridge_interfaces
!= NULL
) ? CFArrayGetCount(a_bridge_interfaces
) : 0;
1053 for (a
= 0; a
< a_count
; a
++) {
1054 SCNetworkInterfaceRef a_interface
;
1055 CFStringRef a_interface_if
;
1057 a_interface
= CFArrayGetValueAtIndex(a_bridge_interfaces
, a
);
1058 if ((c_count
== 0) ||
1059 !CFArrayContainsValue(c_bridge_interfaces
,
1060 CFRangeMake(0, c_count
),
1063 * if this device is no longer part
1067 s
= inet_dgram_socket();
1075 a_interface_if
= SCNetworkInterfaceGetBSDName(a_interface
);
1076 if (!__bridge_remove_interface(s
, a_bridge_if
, a_interface_if
)) {
1089 * if this interface is no longer configured
1092 s
= inet_dgram_socket();
1100 if (!__destroyInterface(s
, a_bridge_if
)) {
1108 * add any newly-configured bridge interfaces and add any
1109 * devices that should now be associated with the bridge.
1111 for (i
= 0; i
< nConfig
; i
++) {
1112 SCBridgeInterfaceRef c_bridge
;
1113 CFArrayRef c_bridge_interfaces
;
1114 CFStringRef c_bridge_if
;
1116 Boolean found
= FALSE
;
1119 c_bridge
= CFArrayGetValueAtIndex(config
, i
);
1120 c_bridge_if
= SCNetworkInterfaceGetBSDName(c_bridge
);
1121 c_bridge_interfaces
= SCBridgeInterfaceGetMemberInterfaces(c_bridge
);
1122 c_count
= (c_bridge_interfaces
!= NULL
) ? CFArrayGetCount(c_bridge_interfaces
) : 0;
1124 for (j
= 0; j
< nActive
; j
++) {
1125 SCBridgeInterfaceRef a_bridge
;
1126 CFArrayRef a_bridge_interfaces
;
1127 CFStringRef a_bridge_if
;
1130 a_bridge
= CFArrayGetValueAtIndex(active
, j
);
1131 a_bridge_if
= SCNetworkInterfaceGetBSDName(a_bridge
);
1132 a_bridge_interfaces
= SCBridgeInterfaceGetMemberInterfaces(a_bridge
);
1133 a_count
= (a_bridge_interfaces
!= NULL
) ? CFArrayGetCount(a_bridge_interfaces
) : 0;
1135 if (CFEqual(c_bridge_if
, a_bridge_if
)) {
1137 Boolean if_list_change
= FALSE
;
1141 if (!_SC_CFEqual(c_bridge_interfaces
, a_bridge_interfaces
)) {
1142 if_list_change
= TRUE
;
1144 if (!if_list_change
) {
1145 break; // if no change
1148 s
= inet_dgram_socket();
1155 if (!if_list_change
) {
1156 break; // no if list changes
1160 * ensure that the first device of the bridge matches, if
1161 * not then we remove all current devices and add them
1162 * back in the preferred order.
1164 if ((c_count
> 0) &&
1166 !CFEqual(CFArrayGetValueAtIndex(c_bridge_interfaces
, 0),
1167 CFArrayGetValueAtIndex(a_bridge_interfaces
, 0))) {
1170 for (a
= 0; a
< a_count
; a
++) {
1171 SCNetworkInterfaceRef a_interface
;
1172 CFStringRef a_interface_if
;
1174 a_interface
= CFArrayGetValueAtIndex(a_bridge_interfaces
, a
);
1175 if (!CFArrayContainsValue(c_bridge_interfaces
,
1176 CFRangeMake(0, c_count
),
1178 continue; // if already removed
1181 a_interface_if
= SCNetworkInterfaceGetBSDName(a_interface
);
1182 if (!__bridge_remove_interface(s
, a_bridge_if
, a_interface_if
)) {
1187 a_count
= 0; // all active devices have been removed
1191 * add any devices which are not currently associated
1192 * with the bridge interface.
1194 for (c
= 0; c
< c_count
; c
++) {
1195 SCNetworkInterfaceRef c_interface
;
1196 SCNetworkInterfacePrivateRef c_interfacePrivate
;
1197 CFStringRef c_interface_if
;
1199 c_interface
= CFArrayGetValueAtIndex(c_bridge_interfaces
, c
);
1200 if ((a_count
== 0) ||
1201 !CFArrayContainsValue(a_bridge_interfaces
,
1202 CFRangeMake(0, a_count
),
1205 * check if this member interface can be added to a bridge.
1207 c_interfacePrivate
= (SCNetworkInterfacePrivateRef
)c_interface
;
1208 if (!c_interfacePrivate
->supportsBridge
) {
1209 // if member not supported
1214 * if this member interface is not currently part of the bridge.
1216 c_interface_if
= SCNetworkInterfaceGetBSDName(c_interface
);
1217 if (!__bridge_add_interface(s
, c_bridge_if
, c_interface_if
)) {
1218 // if member could not be added
1232 s
= inet_dgram_socket();
1241 * establish the new bridge interface.
1243 if (!__createInterface(s
, c_bridge_if
)) {
1250 * add the member interfaces
1252 for (c
= 0; c
< c_count
; c
++) {
1253 SCNetworkInterfaceRef c_interface
;
1254 SCNetworkInterfacePrivateRef c_interfacePrivate
;
1255 CFStringRef c_interface_if
;
1257 c_interface
= CFArrayGetValueAtIndex(c_bridge_interfaces
, c
);
1258 c_interfacePrivate
= (SCNetworkInterfacePrivateRef
)c_interface
;
1259 if (!c_interfacePrivate
->supportsBridge
) {
1260 // if member not supported
1264 c_interface_if
= SCNetworkInterfaceGetBSDName(c_interface
);
1265 if (!__bridge_add_interface(s
, c_bridge_if
, c_interface_if
)) {
1266 // if member could not be added
1276 if (active
!= NULL
) CFRelease(active
);
1277 if (config
!= NULL
) CFRelease(config
);
1278 if (s
!= -1) (void) close(s
);
1283 #endif // IFT_BRIDGE