]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/BridgeConfiguration.c
configd-801.1.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / BridgeConfiguration.c
1 /*
2 * Copyright (c) 2009-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * July 27, 2009 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include "SCNetworkConfigurationInternal.h"
37 #include "SCPreferencesInternal.h"
38 #include <SystemConfiguration/SCValidation.h>
39 #include <SystemConfiguration/SCPrivate.h>
40
41 #include <ifaddrs.h>
42 #include <pthread.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <net/ethernet.h>
49 #define KERNEL_PRIVATE
50 #include <net/if.h>
51 #include <net/if_var.h>
52 #undef KERNEL_PRIVATE
53 #include <net/if_types.h>
54 #include <net/if_media.h>
55 #include <net/route.h>
56
57 #ifdef IFT_BRIDGE
58 #include <net/if_bridgevar.h>
59 #endif // IFT_BRIDGE
60
61 /* ---------- Bridge support ---------- */
62
63 static int
64 inet_dgram_socket()
65 {
66 int s;
67
68 s = socket(AF_INET, SOCK_DGRAM, 0);
69 if (s == -1) {
70 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
71 }
72
73 return s;
74 }
75
76 #ifdef IFT_BRIDGE
77 static struct ifbifconf *
78 ifbifconf_copy(int s, const char * ifname)
79 {
80 void * buf;
81 size_t buflen;
82 struct ifbifconf * ibc_p = NULL;
83 struct ifdrv ifd;
84 uint32_t len = sizeof(struct ifbreq) * 16;
85
86 bzero(&ifd, sizeof(ifd));
87 strncpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
88 ifd.ifd_cmd = BRDGGIFS;
89
90 buflen = sizeof(struct ifbifconf) + len;
91 buf = malloc(buflen);
92 while (buf != NULL) {
93 bzero(buf, buflen);
94 ibc_p = (struct ifbifconf *)buf;
95 ibc_p->ifbic_len = len;
96 ibc_p->ifbic_buf = buf + sizeof(*ibc_p);
97
98 ifd.ifd_len = sizeof(*ibc_p);
99 ifd.ifd_data = ibc_p;
100 if (ioctl(s, SIOCGDRVSPEC, (caddr_t)&ifd) == -1) {
101 goto failed;
102 }
103
104 if ((ibc_p->ifbic_len + sizeof(struct ifbreq)) < len) {
105 // if we have room for all of the member interfaces
106 break;
107 }
108
109 len *= 2;
110 buflen = sizeof(struct ifbifconf) + len;
111 buf = reallocf(buf, buflen);
112 }
113
114 if (buf == NULL) {
115 goto failed;
116 }
117
118 return ibc_p;
119
120 failed:
121 if (buf != NULL) {
122 free(buf);
123 }
124 return NULL;
125 }
126 #endif // IFT_BRIDGE
127
128
129 static void
130 add_interface(CFMutableArrayRef *interfaces, CFStringRef if_name, SCPreferencesRef ni_prefs)
131 {
132 SCNetworkInterfaceRef interface = NULL;
133
134 if (*interfaces == NULL) {
135 *interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
136 }
137 if (ni_prefs != NULL) {
138 interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, if_name);
139 }
140 if (interface == NULL) {
141 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, if_name,
142 kIncludeNoVirtualInterfaces);
143 }
144
145 if (interface != NULL) {
146 CFArrayAppendValue(*interfaces, interface);
147 CFRelease(interface);
148 }
149 }
150
151 typedef struct {
152 CFMutableArrayRef bridges;
153 SCPreferencesRef ni_prefs;
154 SCPreferencesRef prefs;
155 } addContext, *addContextRef;
156
157
158 static void
159 add_configured_interface(const void *key, const void *value, void *context)
160 {
161 SCBridgeInterfaceRef bridge;
162 CFStringRef bridge_if = (CFStringRef)key;
163 CFDictionaryRef bridge_info = (CFDictionaryRef)value;
164 CFDictionaryRef bridge_options;
165 CFIndex i;
166 CFArrayRef interfaces;
167 SCNetworkInterfacePrivateRef interfacePrivate;
168 CFMutableArrayRef members = NULL;
169 addContextRef myContext = (addContextRef)context;
170 CFStringRef name;
171 CFStringRef name_auto = NULL;
172 CFIndex n;
173
174 // create the bridge interface
175 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if);
176 assert(bridge != NULL);
177
178 // estabish link to the stored configuration
179 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
180 interfacePrivate->prefs = CFRetain(myContext->prefs);
181
182 // add member interfaces
183 interfaces = CFDictionaryGetValue(bridge_info, kSCPropVirtualNetworkInterfacesBridgeInterfaces);
184 n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0;
185 for (i = 0; i < n; i++) {
186 CFStringRef member;
187
188 member = CFArrayGetValueAtIndex(interfaces, i);
189 if (isA_CFString(member)) {
190 add_interface(&members, member, myContext->ni_prefs);
191 }
192 }
193 if (members != NULL) {
194 __SCBridgeInterfaceSetMemberInterfaces(bridge, members);
195 CFRelease(members);
196 }
197
198 // set options
199 bridge_options = CFDictionaryGetValue(bridge_info, kSCPropVirtualNetworkInterfacesBridgeOptions);
200 if (isA_CFDictionary(bridge_options)) {
201 SCBridgeInterfaceSetOptions(bridge, bridge_options);
202 name_auto = CFDictionaryGetValue(bridge_options, CFSTR("__AUTO__"));
203 }
204
205 // set display name
206 name = CFDictionaryGetValue(bridge_info, kSCPropUserDefinedName);
207 if (isA_CFString(name)) {
208 SCBridgeInterfaceSetLocalizedDisplayName(bridge, name);
209 } else if (isA_CFString(name_auto)) {
210 interfacePrivate->localized_key = name_auto;
211 if (interfacePrivate->localized_arg1 != NULL) {
212 CFRelease(interfacePrivate->localized_arg1);
213 interfacePrivate->localized_arg1 = NULL;
214 }
215 }
216
217 CFArrayAppendValue(myContext->bridges, bridge);
218 CFRelease(bridge);
219
220 return;
221 }
222
223
224 #pragma mark -
225 #pragma mark SCBridgeInterface APIs
226
227
228 static __inline__ void
229 my_CFDictionaryApplyFunction(CFDictionaryRef theDict,
230 CFDictionaryApplierFunction applier,
231 void *context)
232 {
233 CFAllocatorRef myAllocator;
234 CFDictionaryRef myDict;
235
236 myAllocator = CFGetAllocator(theDict);
237 myDict = CFDictionaryCreateCopy(myAllocator, theDict);
238 CFDictionaryApplyFunction(myDict, applier, context);
239 CFRelease(myDict);
240 return;
241 }
242
243
244 CFArrayRef
245 SCBridgeInterfaceCopyAll(SCPreferencesRef prefs)
246 {
247 addContext context;
248 CFDictionaryRef dict;
249 SCPreferencesRef ni_prefs;
250 CFStringRef path;
251
252 if ((prefs == NULL) ||
253 (__SCPreferencesUsingDefaultPrefs(prefs) == TRUE)) {
254 ni_prefs = NULL;
255 }
256 else {
257 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs);
258 }
259 context.bridges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
260 context.prefs = prefs;
261 context.ni_prefs = ni_prefs;
262
263 path = CFStringCreateWithFormat(NULL,
264 NULL,
265 CFSTR("/%@/%@"),
266 kSCPrefVirtualNetworkInterfaces,
267 kSCNetworkInterfaceTypeBridge);
268 dict = SCPreferencesPathGetValue(prefs, path);
269 if (isA_CFDictionary(dict)) {
270 my_CFDictionaryApplyFunction(dict, add_configured_interface, &context);
271 }
272 CFRelease(path);
273 if (ni_prefs != NULL) {
274 CFRelease(ni_prefs);
275 }
276 return context.bridges;
277 }
278
279
280 __private_extern__ void
281 __SCBridgeInterfaceListCollectMembers(CFArrayRef interfaces, CFMutableSetRef set)
282 {
283 CFIndex i;
284 CFIndex n;
285
286 n = CFArrayGetCount(interfaces);
287 for (i = 0; i < n; i++) {
288 SCBridgeInterfaceRef bridgeInterface;
289 CFArrayRef members;
290
291 bridgeInterface = CFArrayGetValueAtIndex(interfaces, i);
292 members = SCBridgeInterfaceGetMemberInterfaces(bridgeInterface);
293 if (members != NULL) {
294 CFIndex j;
295 CFIndex n_members;
296
297 // exclude the member interfaces of this bridge
298 n_members = CFArrayGetCount(members);
299 for (j = 0; j < n_members; j++) {
300 SCNetworkInterfaceRef member;
301
302 member = CFArrayGetValueAtIndex(members, j);
303 CFSetAddValue(set, member);
304 }
305 }
306
307 }
308 return;
309 }
310
311
312 CFArrayRef /* of SCNetworkInterfaceRef's */
313 SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs)
314 {
315 CFMutableArrayRef available;
316 CFMutableSetRef excluded;
317 CFArrayRef interfaces;
318
319 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
320 excluded = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks);
321
322 #if !TARGET_OS_IPHONE
323 // exclude Bond [member] interfaces
324 interfaces = SCBondInterfaceCopyAll(prefs);
325 if (interfaces != NULL) {
326 __SCBondInterfaceListCollectMembers(interfaces, excluded);
327 CFRelease(interfaces);
328 }
329 #endif // !TARGET_OS_IPHONE
330
331 // exclude Bridge [member] interfaces
332 interfaces = SCBridgeInterfaceCopyAll(prefs);
333 if (interfaces != NULL) {
334 __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
335 CFRelease(interfaces);
336 }
337
338 // exclude VLAN [physical] interfaces
339 interfaces = SCVLANInterfaceCopyAll(prefs);
340 if (interfaces != NULL) {
341 CFIndex i;
342 CFIndex n;
343
344 n = CFArrayGetCount(interfaces);
345 for (i = 0; i < n; i++) {
346 SCVLANInterfaceRef vlanInterface;
347 SCNetworkInterfaceRef physical;
348
349 // exclude the physical interface of this VLAN
350 vlanInterface = CFArrayGetValueAtIndex(interfaces, i);
351 physical = SCVLANInterfaceGetPhysicalInterface(vlanInterface);
352 CFSetAddValue(excluded, physical);
353 }
354 CFRelease(interfaces);
355 }
356
357 // identify available interfaces
358 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
359 if (interfaces != NULL) {
360 CFIndex i;
361 CFIndex n;
362
363 n = CFArrayGetCount(interfaces);
364 for (i = 0; i < n; i++) {
365 SCNetworkInterfaceRef interface;
366 SCNetworkInterfacePrivateRef interfacePrivate;
367
368 interface = CFArrayGetValueAtIndex(interfaces, i);
369 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
370
371 if (!interfacePrivate->supportsBridge) {
372 // if this interface is not available
373 continue;
374 }
375
376 if (CFSetContainsValue(excluded, interface)) {
377 // if excluded
378 continue;
379 }
380
381 CFArrayAppendValue(available, interface);
382 }
383 CFRelease(interfaces);
384 }
385
386 CFRelease(excluded);
387
388 return available;
389 }
390
391
392 CFArrayRef
393 _SCBridgeInterfaceCopyActive(void)
394 {
395 struct ifaddrs *ifap;
396 struct ifaddrs *ifp;
397 int s;
398 CFMutableArrayRef bridges = NULL;
399
400 if (getifaddrs(&ifap) == -1) {
401 _SCErrorSet(errno);
402 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
403 return NULL;
404 }
405
406 s = inet_dgram_socket();
407 if (s == -1) {
408 _SCErrorSet(errno);
409 goto done;
410 }
411
412 bridges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
413
414 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
415 #ifdef IFT_BRIDGE
416 SCBridgeInterfaceRef bridge;
417 CFStringRef bridge_if;
418 struct ifbifconf *ibc_p;
419 struct if_data *if_data;
420 CFMutableArrayRef members = NULL;
421 size_t n;
422
423 if_data = (struct if_data *)ifp->ifa_data;
424 if (if_data == NULL
425 || ifp->ifa_addr->sa_family != AF_LINK
426 || if_data->ifi_type != IFT_BRIDGE) {
427 continue;
428 }
429
430 // make sure that we leave non-SC configured bridge
431 // interfaces (those with unit #'s >= 100) alone.
432 n = strlen(ifp->ifa_name);
433 if ((n > 3) &&
434 isdigit(ifp->ifa_name[n - 1]) &&
435 isdigit(ifp->ifa_name[n - 2]) &&
436 isdigit(ifp->ifa_name[n - 3])) {
437 // if not SC managed bridge interface
438 continue;
439 }
440
441 ibc_p = ifbifconf_copy(s, ifp->ifa_name);
442 if (ibc_p == NULL) {
443 if (errno == EBUSY) {
444 continue;
445 }
446 _SCErrorSet(errno);
447 SC_log(LOG_NOTICE, "ifbifconf_copy(%s) failed: %s",
448 ifp->ifa_name,
449 strerror(errno));
450 CFRelease(bridges);
451 bridges = NULL;
452 goto done;
453 }
454
455 // create the bridge interface
456 bridge_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
457 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if);
458 CFRelease(bridge_if);
459
460 // add member interfaces
461 if (ibc_p->ifbic_len > 0) {
462 int i;
463
464 // iterate over each member interface
465 for (i = 0; i < ibc_p->ifbic_len / sizeof(struct ifbreq); i++) {
466 struct ifbreq *ibr_p;
467 CFStringRef member;
468
469 ibr_p = ibc_p->ifbic_req + i;
470 member = CFStringCreateWithCString(NULL, ibr_p->ifbr_ifsname, kCFStringEncodingASCII);
471 add_interface(&members, member, NULL);
472 CFRelease(member);
473 }
474 }
475 free(ibc_p);
476
477 if (members != NULL) {
478 __SCBridgeInterfaceSetMemberInterfaces(bridge, members);
479 CFRelease(members);
480 }
481
482 // add bridge
483 CFArrayAppendValue(bridges, bridge);
484 CFRelease(bridge);
485 #endif // IFT_BRIDGE
486 }
487
488 done :
489
490 if (s != -1) {
491 (void) close(s);
492 }
493 freeifaddrs(ifap);
494 return bridges;
495 }
496
497
498 SCBridgeInterfaceRef
499 SCBridgeInterfaceCreate(SCPreferencesRef prefs)
500 {
501 CFAllocatorRef allocator;
502 SCBridgeInterfaceRef bridge = NULL;
503 CFIndex i;
504
505 if (prefs == NULL) {
506 _SCErrorSet(kSCStatusInvalidArgument);
507 return NULL;
508 }
509
510 allocator = CFGetAllocator(prefs);
511
512 // create a new bridge using an unused interface name
513 for (i = 0; bridge == NULL; i++) {
514 CFDictionaryRef dict;
515 CFStringRef bridge_if;
516 SCNetworkInterfacePrivateRef interfacePrivate;
517 CFMutableDictionaryRef newDict;
518 CFArrayRef newInterfaces;
519 Boolean ok;
520 CFStringRef path;
521
522 bridge_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bridge%ld"), i);
523 path = CFStringCreateWithFormat(allocator,
524 NULL,
525 CFSTR("/%@/%@/%@"),
526 kSCPrefVirtualNetworkInterfaces,
527 kSCNetworkInterfaceTypeBridge,
528 bridge_if);
529 dict = SCPreferencesPathGetValue(prefs, path);
530 if (dict != NULL) {
531 // if bridge interface name not available
532 CFRelease(path);
533 CFRelease(bridge_if);
534 continue;
535 }
536
537 // add the bridge to the stored preferences
538 newDict = CFDictionaryCreateMutable(allocator,
539 0,
540 &kCFTypeDictionaryKeyCallBacks,
541 &kCFTypeDictionaryValueCallBacks);
542 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks);
543 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newInterfaces);
544 CFRelease(newInterfaces);
545 ok = SCPreferencesPathSetValue(prefs, path, newDict);
546 CFRelease(newDict);
547 CFRelease(path);
548 if (!ok) {
549 // if the bridge could not be saved
550 CFRelease(bridge_if);
551 break;
552 }
553
554 // create the SCBridgeInterfaceRef
555 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(allocator, bridge_if);
556 CFRelease(bridge_if);
557
558 // estabish link to the stored configuration
559 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
560 interfacePrivate->prefs = CFRetain(prefs);
561 }
562
563 return bridge;
564 }
565
566
567 Boolean
568 SCBridgeInterfaceRemove(SCBridgeInterfaceRef bridge)
569 {
570 CFStringRef bridge_if;
571 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
572 Boolean ok;
573 CFStringRef path;
574
575 if (!isA_SCBridgeInterface(bridge)) {
576 _SCErrorSet(kSCStatusInvalidArgument);
577 return FALSE;
578 }
579
580 if (interfacePrivate->prefs == NULL) {
581 _SCErrorSet(kSCStatusInvalidArgument);
582 return FALSE;
583 }
584
585 bridge_if = SCNetworkInterfaceGetBSDName(bridge);
586 path = CFStringCreateWithFormat(NULL,
587 NULL,
588 CFSTR("/%@/%@/%@"),
589 kSCPrefVirtualNetworkInterfaces,
590 kSCNetworkInterfaceTypeBridge,
591 bridge_if);
592 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
593 CFRelease(path);
594
595 return ok;
596 }
597
598
599 CFArrayRef
600 SCBridgeInterfaceGetMemberInterfaces(SCBridgeInterfaceRef bridge)
601 {
602 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
603
604 if (!isA_SCBridgeInterface(bridge)) {
605 _SCErrorSet(kSCStatusInvalidArgument);
606 return NULL;
607 }
608
609 return interfacePrivate->bridge.interfaces;
610 }
611
612
613 CFDictionaryRef
614 SCBridgeInterfaceGetOptions(SCBridgeInterfaceRef bridge)
615 {
616 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
617
618 if (!isA_SCBridgeInterface(bridge)) {
619 _SCErrorSet(kSCStatusInvalidArgument);
620 return NULL;
621 }
622
623 return interfacePrivate->bridge.options;
624 }
625
626
627 __private_extern__
628 Boolean
629 __SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members)
630 {
631 CFIndex i;
632 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
633 CFIndex n;
634 CFMutableArrayRef newMembers;
635 Boolean ok = TRUE;
636
637 n = (members != NULL) ? CFArrayGetCount(members) : 0;
638
639 // set member interfaces in the stored preferences
640 if (interfacePrivate->prefs != NULL) {
641 CFDictionaryRef dict;
642 CFMutableDictionaryRef newDict;
643 CFStringRef path;
644
645 path = CFStringCreateWithFormat(NULL,
646 NULL,
647 CFSTR("/%@/%@/%@"),
648 kSCPrefVirtualNetworkInterfaces,
649 kSCNetworkInterfaceTypeBridge,
650 interfacePrivate->entity_device);
651 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
652 if (!isA_CFDictionary(dict)) {
653 // if the prefs are confused
654 CFRelease(path);
655 _SCErrorSet(kSCStatusFailed);
656 return FALSE;
657 }
658
659 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
660 for (i = 0; i < n; i++) {
661 SCNetworkInterfaceRef interface;
662 CFStringRef memberName;
663
664 interface = CFArrayGetValueAtIndex(members, i);
665 memberName = SCNetworkInterfaceGetBSDName(interface);
666 CFArrayAppendValue(newMembers, memberName);
667 }
668
669 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
670 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newMembers);
671 CFRelease(newMembers);
672 if (!CFEqual(dict, newDict)) {
673 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
674 }
675 CFRelease(newDict);
676 CFRelease(path);
677 }
678
679 if (ok) {
680 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
681 for (i = 0; i < n; i++) {
682 SCNetworkInterfaceRef member;
683 SCNetworkInterfacePrivateRef newMember;
684
685 member = CFArrayGetValueAtIndex(members, i);
686 newMember = __SCNetworkInterfaceCreateCopy(NULL,
687 member,
688 interfacePrivate->prefs,
689 interfacePrivate->serviceID);
690 CFArrayAppendValue(newMembers, newMember);
691 CFRelease(newMember);
692 }
693 CFRelease(interfacePrivate->bridge.interfaces);
694 interfacePrivate->bridge.interfaces = newMembers;
695 }
696
697 return ok;
698 }
699
700
701 Boolean
702 SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members)
703 {
704 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
705 Boolean ok;
706 int sc_status = kSCStatusOK;
707
708 if (!isA_SCBridgeInterface(bridge)) {
709 _SCErrorSet(kSCStatusInvalidArgument);
710 return FALSE;
711 }
712
713 if ((members != NULL) && !isA_CFArray(members)) {
714 _SCErrorSet(kSCStatusInvalidArgument);
715 return FALSE;
716 }
717
718 if (interfacePrivate->prefs != NULL) {
719 CFArrayRef available;
720 CFArrayRef current;
721 CFIndex i;
722 CFIndex n_available;
723 CFIndex n_current;
724 CFIndex n_members;
725 CFArrayRef services = NULL;
726
727 current = SCBridgeInterfaceGetMemberInterfaces(bridge);
728 n_current = (current != NULL) ? CFArrayGetCount(current) : 0;
729
730 available = SCBridgeInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs);
731 n_available = (available != NULL) ? CFArrayGetCount(available) : 0;
732
733 n_members = (members != NULL) ? CFArrayGetCount(members) : 0;
734 for (i = 0; i < n_members; i++) {
735 SCNetworkInterfaceRef member;
736
737 member = CFArrayGetValueAtIndex(members, i);
738
739 if ((current != NULL) &&
740 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) {
741 // current members are allowed
742 continue;
743 }
744
745 if ((available != NULL) &&
746 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) {
747 // available members are allowed but cannot be associated
748 // with any other network services.
749
750 if (services == NULL) {
751 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs);
752 }
753 if ((services != NULL) &&
754 __SCNetworkServiceExistsForInterface(services, member)) {
755 sc_status = kSCStatusKeyExists;
756 break;
757 }
758
759 // if available
760 continue;
761 }
762
763 // if member not allowed
764 sc_status = kSCStatusInvalidArgument;
765 break;
766 }
767
768 if (available != NULL) CFRelease(available);
769 if (services != NULL) CFRelease(services);
770 }
771
772 if (sc_status != kSCStatusOK) {
773 _SCErrorSet(sc_status);
774 return FALSE;
775 }
776
777 ok = __SCBridgeInterfaceSetMemberInterfaces(bridge, members);
778 return ok;
779 }
780
781
782 Boolean
783 SCBridgeInterfaceSetLocalizedDisplayName(SCBridgeInterfaceRef bridge, CFStringRef newName)
784 {
785 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
786 Boolean ok = TRUE;
787
788 if (!isA_SCBridgeInterface(bridge)) {
789 _SCErrorSet(kSCStatusInvalidArgument);
790 return FALSE;
791 }
792
793 if ((newName != NULL) && !isA_CFString(newName)) {
794 _SCErrorSet(kSCStatusInvalidArgument);
795 return FALSE;
796 }
797
798 // set name in the stored preferences
799 if (interfacePrivate->prefs != NULL) {
800 CFDictionaryRef dict;
801 CFMutableDictionaryRef newDict;
802 CFStringRef path;
803
804 path = CFStringCreateWithFormat(NULL,
805 NULL,
806 CFSTR("/%@/%@/%@"),
807 kSCPrefVirtualNetworkInterfaces,
808 kSCNetworkInterfaceTypeBridge,
809 interfacePrivate->entity_device);
810 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
811 if (!isA_CFDictionary(dict)) {
812 // if the prefs are confused
813 CFRelease(path);
814 _SCErrorSet(kSCStatusFailed);
815 return FALSE;
816 }
817
818 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
819 if (newName != NULL) {
820 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
821 } else {
822 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
823 }
824 if (!CFEqual(dict, newDict)) {
825 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
826 }
827 CFRelease(newDict);
828 CFRelease(path);
829 }
830
831 // set name in the SCBridgeInterfaceRef
832 if (ok) {
833 if (interfacePrivate->localized_name != NULL) {
834 CFRelease(interfacePrivate->localized_name);
835 interfacePrivate->localized_name = NULL;
836 }
837 if (newName != NULL) {
838 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
839 }
840 }
841
842 return ok;
843 }
844
845
846 Boolean
847 SCBridgeInterfaceSetOptions(SCBridgeInterfaceRef bridge, CFDictionaryRef newOptions)
848 {
849 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
850 Boolean ok = TRUE;
851
852 if (!isA_SCBridgeInterface(bridge)) {
853 _SCErrorSet(kSCStatusInvalidArgument);
854 return FALSE;
855 }
856
857 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
858 _SCErrorSet(kSCStatusInvalidArgument);
859 return FALSE;
860 }
861
862 // set options in the stored preferences
863 if (interfacePrivate->prefs != NULL) {
864 CFDictionaryRef dict;
865 CFMutableDictionaryRef newDict;
866 CFStringRef path;
867
868 path = CFStringCreateWithFormat(NULL,
869 NULL,
870 CFSTR("/%@/%@/%@"),
871 kSCPrefVirtualNetworkInterfaces,
872 kSCNetworkInterfaceTypeBridge,
873 interfacePrivate->entity_device);
874 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
875 if (!isA_CFDictionary(dict)) {
876 // if the prefs are confused
877 CFRelease(path);
878 _SCErrorSet(kSCStatusFailed);
879 return FALSE;
880 }
881
882 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
883 if (newOptions != NULL) {
884 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions, newOptions);
885 } else {
886 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions);
887 }
888 if (!CFEqual(dict, newDict)) {
889 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
890 }
891 CFRelease(newDict);
892 CFRelease(path);
893 }
894
895 // set options in the SCBridgeInterfaceRef
896 if (ok) {
897 if (interfacePrivate->bridge.options != NULL) {
898 CFRelease(interfacePrivate->bridge.options);
899 interfacePrivate->bridge.options = NULL;
900 }
901 if (newOptions != NULL) {
902 CFStringRef name_auto = NULL;
903
904 interfacePrivate->bridge.options = CFDictionaryCreateCopy(NULL, newOptions);
905
906 // set [auto] display name from options
907 if ((interfacePrivate->localized_name == NULL) &&
908 CFDictionaryGetValueIfPresent(newOptions,
909 CFSTR("__AUTO__"),
910 (const void **)&name_auto) &&
911 isA_CFString(name_auto)) {
912 // set display name
913 interfacePrivate->localized_key = name_auto;
914 if (interfacePrivate->localized_arg1 != NULL) {
915 CFRelease(interfacePrivate->localized_arg1);
916 interfacePrivate->localized_arg1 = NULL;
917 }
918 }
919 }
920 }
921
922 return ok;
923 }
924
925
926 #pragma mark -
927 #pragma mark SCBridgeInterface management
928
929
930 #ifdef IFT_BRIDGE
931 static Boolean
932 __bridge_add_interface(int s, CFStringRef bridge_if, CFStringRef interface_if)
933 {
934 struct ifbreq breq;
935 struct ifdrv ifd;
936
937 // bridge interface
938 bzero(&ifd, sizeof(ifd));
939 (void) _SC_cfstring_to_cstring(bridge_if,
940 ifd.ifd_name,
941 sizeof(ifd.ifd_name),
942 kCFStringEncodingASCII);
943 ifd.ifd_cmd = BRDGADD;
944 ifd.ifd_len = sizeof(breq);
945 ifd.ifd_data = (caddr_t)&breq;
946
947 // new bridge member
948 bzero(&breq, sizeof(breq));
949 (void) _SC_cfstring_to_cstring(interface_if,
950 breq.ifbr_ifsname,
951 sizeof(breq.ifbr_ifsname),
952 kCFStringEncodingASCII);
953
954 // add new bridge member
955 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) {
956 _SCErrorSet(errno);
957 SC_log(LOG_ERR, "could not add interface \"%@\" to bridge \"%@\": %s",
958 interface_if,
959 bridge_if,
960 strerror(errno));
961 return FALSE;
962 }
963
964 return TRUE;
965 }
966
967
968 static Boolean
969 __bridge_remove_interface(int s, CFStringRef bridge_if, CFStringRef interface_if)
970 {
971 struct ifbreq breq;
972 struct ifdrv ifd;
973
974 // bridge interface
975 bzero(&ifd, sizeof(ifd));
976 (void) _SC_cfstring_to_cstring(bridge_if,
977 ifd.ifd_name,
978 sizeof(ifd.ifd_name),
979 kCFStringEncodingASCII);
980 ifd.ifd_cmd = BRDGDEL;
981 ifd.ifd_len = sizeof(breq);
982 ifd.ifd_data = (caddr_t)&breq;
983
984 // bridge member to remove
985 bzero(&breq, sizeof(breq));
986 (void) _SC_cfstring_to_cstring(interface_if,
987 breq.ifbr_ifsname,
988 sizeof(breq.ifbr_ifsname),
989 kCFStringEncodingASCII);
990
991 // remove bridge member
992 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) {
993 _SCErrorSet(errno);
994 SC_log(LOG_ERR, "could not remove interface \"%@\" from bridge \"%@\": %s",
995 interface_if,
996 bridge_if,
997 strerror(errno));
998 return FALSE;
999 }
1000
1001 return TRUE;
1002 }
1003 #endif // IFT_BRIDGE
1004
1005
1006 Boolean
1007 _SCBridgeInterfaceUpdateConfiguration(SCPreferencesRef prefs)
1008 {
1009 #ifdef IFT_BRIDGE
1010 CFArrayRef active = NULL;
1011 CFArrayRef config = NULL;
1012 CFIndex i;
1013 CFIndex nActive;
1014 CFIndex nConfig;
1015 Boolean ok = TRUE;
1016 int s = -1;
1017
1018 if (prefs == NULL) {
1019 _SCErrorSet(kSCStatusInvalidArgument);
1020 return FALSE;
1021 }
1022
1023 /* configured Bridges */
1024 config = SCBridgeInterfaceCopyAll(prefs);
1025 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
1026
1027 /* active Bridges */
1028 active = _SCBridgeInterfaceCopyActive();
1029 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
1030
1031 /*
1032 * remove any no-longer-configured bridge interfaces and
1033 * any devices associated with a bridge that are no longer
1034 * associated with a bridge.
1035 */
1036 for (i = 0; i < nActive; i++) {
1037 SCBridgeInterfaceRef a_bridge;
1038 CFStringRef a_bridge_if;
1039 CFIndex j;
1040 Boolean found = FALSE;
1041
1042 a_bridge = CFArrayGetValueAtIndex(active, i);
1043 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge);
1044
1045 for (j = 0; j < nConfig; j++) {
1046 SCBridgeInterfaceRef c_bridge;
1047 CFStringRef c_bridge_if;
1048
1049 c_bridge = CFArrayGetValueAtIndex(config, j);
1050 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge);
1051
1052 if (CFEqual(a_bridge_if, c_bridge_if)) {
1053 CFIndex a;
1054 CFArrayRef a_bridge_interfaces;
1055 CFIndex a_count;
1056 CFArrayRef c_bridge_interfaces;
1057 CFIndex c_count;
1058
1059 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge);
1060 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0;
1061
1062 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge);
1063 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0;
1064
1065 for (a = 0; a < a_count; a++) {
1066 SCNetworkInterfaceRef a_interface;
1067 CFStringRef a_interface_if;
1068
1069 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a);
1070 if ((c_count == 0) ||
1071 !CFArrayContainsValue(c_bridge_interfaces,
1072 CFRangeMake(0, c_count),
1073 a_interface)) {
1074 /*
1075 * if this device is no longer part
1076 * of the bridge.
1077 */
1078 if (s == -1) {
1079 s = inet_dgram_socket();
1080 if (s == -1) {
1081 _SCErrorSet(errno);
1082 ok = FALSE;
1083 goto done;
1084 }
1085 }
1086
1087 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1088 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) {
1089 ok = FALSE;
1090 }
1091 }
1092 }
1093
1094 found = TRUE;
1095 break;
1096 }
1097 }
1098
1099 if (!found) {
1100 /*
1101 * if this interface is no longer configured
1102 */
1103 if (s == -1) {
1104 s = inet_dgram_socket();
1105 if (s == -1) {
1106 _SCErrorSet(errno);
1107 ok = FALSE;
1108 goto done;
1109 }
1110 }
1111
1112 if (!__destroyInterface(s, a_bridge_if)) {
1113 _SCErrorSet(errno);
1114 ok = FALSE;
1115 }
1116 }
1117 }
1118
1119 /*
1120 * add any newly-configured bridge interfaces and add any
1121 * devices that should now be associated with the bridge.
1122 */
1123 for (i = 0; i < nConfig; i++) {
1124 SCBridgeInterfaceRef c_bridge;
1125 CFArrayRef c_bridge_interfaces;
1126 CFStringRef c_bridge_if;
1127 CFIndex c_count;
1128 Boolean found = FALSE;
1129 CFIndex j;
1130
1131 c_bridge = CFArrayGetValueAtIndex(config, i);
1132 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge);
1133 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge);
1134 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0;
1135
1136 for (j = 0; j < nActive; j++) {
1137 SCBridgeInterfaceRef a_bridge;
1138 CFArrayRef a_bridge_interfaces;
1139 CFStringRef a_bridge_if;
1140 CFIndex a_count;
1141
1142 a_bridge = CFArrayGetValueAtIndex(active, j);
1143 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge);
1144 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge);
1145 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0;
1146
1147 if (CFEqual(c_bridge_if, a_bridge_if)) {
1148 CFIndex c;
1149 Boolean if_list_change = FALSE;
1150
1151 found = TRUE;
1152
1153 if (!_SC_CFEqual(c_bridge_interfaces, a_bridge_interfaces)) {
1154 if_list_change = TRUE;
1155 }
1156 if (!if_list_change) {
1157 break; // if no change
1158 }
1159 if (s == -1) {
1160 s = inet_dgram_socket();
1161 if (s == -1) {
1162 _SCErrorSet(errno);
1163 ok = FALSE;
1164 goto done;
1165 }
1166 }
1167 if (!if_list_change) {
1168 break; // no if list changes
1169 }
1170
1171 /*
1172 * ensure that the first device of the bridge matches, if
1173 * not then we remove all current devices and add them
1174 * back in the preferred order.
1175 */
1176 if ((c_count > 0) &&
1177 (a_count > 0) &&
1178 !CFEqual(CFArrayGetValueAtIndex(c_bridge_interfaces, 0),
1179 CFArrayGetValueAtIndex(a_bridge_interfaces, 0))) {
1180 CFIndex a;
1181
1182 for (a = 0; a < a_count; a++) {
1183 SCNetworkInterfaceRef a_interface;
1184 CFStringRef a_interface_if;
1185
1186 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a);
1187 if (!CFArrayContainsValue(c_bridge_interfaces,
1188 CFRangeMake(0, c_count),
1189 a_interface)) {
1190 continue; // if already removed
1191 }
1192
1193 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1194 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) {
1195 ok = FALSE;
1196 }
1197 }
1198
1199 a_count = 0; // all active devices have been removed
1200 }
1201
1202 /*
1203 * add any devices which are not currently associated
1204 * with the bridge interface.
1205 */
1206 for (c = 0; c < c_count; c++) {
1207 SCNetworkInterfaceRef c_interface;
1208 SCNetworkInterfacePrivateRef c_interfacePrivate;
1209 CFStringRef c_interface_if;
1210
1211 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c);
1212 if ((a_count == 0) ||
1213 !CFArrayContainsValue(a_bridge_interfaces,
1214 CFRangeMake(0, a_count),
1215 c_interface)) {
1216 /*
1217 * check if this member interface can be added to a bridge.
1218 */
1219 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1220 if (!c_interfacePrivate->supportsBridge) {
1221 // if member not supported
1222 continue;
1223 }
1224
1225 /*
1226 * if this member interface is not currently part of the bridge.
1227 */
1228 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1229 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) {
1230 // if member could not be added
1231 ok = FALSE;
1232 }
1233 }
1234 }
1235
1236 break;
1237 }
1238 }
1239
1240 if (!found) {
1241 CFIndex c;
1242
1243 if (s == -1) {
1244 s = inet_dgram_socket();
1245 if (s == -1) {
1246 _SCErrorSet(errno);
1247 ok = FALSE;
1248 goto done;
1249 }
1250 }
1251
1252 /*
1253 * establish the new bridge interface.
1254 */
1255 if (!__createInterface(s, c_bridge_if)) {
1256 _SCErrorSet(errno);
1257 ok = FALSE;
1258 continue;
1259 }
1260
1261 /*
1262 * add the member interfaces
1263 */
1264 for (c = 0; c < c_count; c++) {
1265 SCNetworkInterfaceRef c_interface;
1266 SCNetworkInterfacePrivateRef c_interfacePrivate;
1267 CFStringRef c_interface_if;
1268
1269 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c);
1270 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1271 if (!c_interfacePrivate->supportsBridge) {
1272 // if member not supported
1273 continue;
1274 }
1275
1276 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1277 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) {
1278 // if member could not be added
1279 ok = FALSE;
1280 }
1281 }
1282 }
1283
1284 }
1285
1286 done :
1287
1288 if (active != NULL) CFRelease(active);
1289 if (config != NULL) CFRelease(config);
1290 if (s != -1) (void) close(s);
1291
1292 return ok;
1293 #else // IFT_BRIDGE
1294 return TRUE;
1295 #endif // IFT_BRIDGE
1296 }