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