ee16a69059a1963fe2c0742544929d1699610a18
[apple/configd.git] / SystemConfiguration.fproj / BridgeConfiguration.c
1 /*
2 * Copyright (c) 2009-2014 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 SCLog(TRUE, LOG_ERR, CFSTR("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 SCLog(TRUE, LOG_ERR, CFSTR("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 SCLog(TRUE, LOG_ERR,
448 CFSTR("ifbifconf_copy(%s) failed: %s"),
449 ifp->ifa_name,
450 strerror(errno));
451 CFRelease(bridges);
452 bridges = NULL;
453 goto done;
454 }
455
456 // create the bridge interface
457 bridge_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
458 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if);
459 CFRelease(bridge_if);
460
461 // add member interfaces
462 if (ibc_p->ifbic_len > 0) {
463 int i;
464
465 // iterate over each member interface
466 for (i = 0; i < ibc_p->ifbic_len / sizeof(struct ifbreq); i++) {
467 struct ifbreq *ibr_p;
468 CFStringRef member;
469
470 ibr_p = ibc_p->ifbic_req + i;
471 member = CFStringCreateWithCString(NULL, ibr_p->ifbr_ifsname, kCFStringEncodingASCII);
472 add_interface(&members, member, NULL);
473 CFRelease(member);
474 }
475 }
476 free(ibc_p);
477
478 if (members != NULL) {
479 __SCBridgeInterfaceSetMemberInterfaces(bridge, members);
480 CFRelease(members);
481 }
482
483 // add bridge
484 CFArrayAppendValue(bridges, bridge);
485 CFRelease(bridge);
486 #endif // IFT_BRIDGE
487 }
488
489 done :
490
491 if (s != -1) {
492 (void) close(s);
493 }
494 freeifaddrs(ifap);
495 return bridges;
496 }
497
498
499 SCBridgeInterfaceRef
500 SCBridgeInterfaceCreate(SCPreferencesRef prefs)
501 {
502 CFAllocatorRef allocator;
503 SCBridgeInterfaceRef bridge = NULL;
504 CFIndex i;
505
506 if (prefs == NULL) {
507 _SCErrorSet(kSCStatusInvalidArgument);
508 return NULL;
509 }
510
511 allocator = CFGetAllocator(prefs);
512
513 // create a new bridge using an unused interface name
514 for (i = 0; bridge == NULL; i++) {
515 CFDictionaryRef dict;
516 CFStringRef bridge_if;
517 SCNetworkInterfacePrivateRef interfacePrivate;
518 CFMutableDictionaryRef newDict;
519 CFArrayRef newInterfaces;
520 Boolean ok;
521 CFStringRef path;
522
523 bridge_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bridge%ld"), i);
524 path = CFStringCreateWithFormat(allocator,
525 NULL,
526 CFSTR("/%@/%@/%@"),
527 kSCPrefVirtualNetworkInterfaces,
528 kSCNetworkInterfaceTypeBridge,
529 bridge_if);
530 dict = SCPreferencesPathGetValue(prefs, path);
531 if (dict != NULL) {
532 // if bridge interface name not available
533 CFRelease(path);
534 CFRelease(bridge_if);
535 continue;
536 }
537
538 // add the bridge to the stored preferences
539 newDict = CFDictionaryCreateMutable(allocator,
540 0,
541 &kCFTypeDictionaryKeyCallBacks,
542 &kCFTypeDictionaryValueCallBacks);
543 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks);
544 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newInterfaces);
545 CFRelease(newInterfaces);
546 ok = SCPreferencesPathSetValue(prefs, path, newDict);
547 CFRelease(newDict);
548 CFRelease(path);
549 if (!ok) {
550 // if the bridge could not be saved
551 CFRelease(bridge_if);
552 break;
553 }
554
555 // create the SCBridgeInterfaceRef
556 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(allocator, bridge_if);
557 CFRelease(bridge_if);
558
559 // estabish link to the stored configuration
560 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
561 interfacePrivate->prefs = CFRetain(prefs);
562 }
563
564 return bridge;
565 }
566
567
568 Boolean
569 SCBridgeInterfaceRemove(SCBridgeInterfaceRef bridge)
570 {
571 CFStringRef bridge_if;
572 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
573 Boolean ok;
574 CFStringRef path;
575
576 if (!isA_SCBridgeInterface(bridge)) {
577 _SCErrorSet(kSCStatusInvalidArgument);
578 return FALSE;
579 }
580
581 if (interfacePrivate->prefs == NULL) {
582 _SCErrorSet(kSCStatusInvalidArgument);
583 return FALSE;
584 }
585
586 bridge_if = SCNetworkInterfaceGetBSDName(bridge);
587 path = CFStringCreateWithFormat(NULL,
588 NULL,
589 CFSTR("/%@/%@/%@"),
590 kSCPrefVirtualNetworkInterfaces,
591 kSCNetworkInterfaceTypeBridge,
592 bridge_if);
593 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
594 CFRelease(path);
595
596 return ok;
597 }
598
599
600 CFArrayRef
601 SCBridgeInterfaceGetMemberInterfaces(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.interfaces;
611 }
612
613
614 CFDictionaryRef
615 SCBridgeInterfaceGetOptions(SCBridgeInterfaceRef bridge)
616 {
617 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
618
619 if (!isA_SCBridgeInterface(bridge)) {
620 _SCErrorSet(kSCStatusInvalidArgument);
621 return NULL;
622 }
623
624 return interfacePrivate->bridge.options;
625 }
626
627
628 __private_extern__
629 Boolean
630 __SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members)
631 {
632 CFIndex i;
633 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
634 CFIndex n;
635 CFMutableArrayRef newMembers;
636 Boolean ok = TRUE;
637
638 n = (members != NULL) ? CFArrayGetCount(members) : 0;
639
640 // set member interfaces in the stored preferences
641 if (interfacePrivate->prefs != NULL) {
642 CFDictionaryRef dict;
643 CFMutableDictionaryRef newDict;
644 CFStringRef path;
645
646 path = CFStringCreateWithFormat(NULL,
647 NULL,
648 CFSTR("/%@/%@/%@"),
649 kSCPrefVirtualNetworkInterfaces,
650 kSCNetworkInterfaceTypeBridge,
651 interfacePrivate->entity_device);
652 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
653 if (!isA_CFDictionary(dict)) {
654 // if the prefs are confused
655 CFRelease(path);
656 _SCErrorSet(kSCStatusFailed);
657 return FALSE;
658 }
659
660 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
661 for (i = 0; i < n; i++) {
662 SCNetworkInterfaceRef interface;
663 CFStringRef memberName;
664
665 interface = CFArrayGetValueAtIndex(members, i);
666 memberName = SCNetworkInterfaceGetBSDName(interface);
667 CFArrayAppendValue(newMembers, memberName);
668 }
669
670 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
671 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newMembers);
672 CFRelease(newMembers);
673 if (!CFEqual(dict, newDict)) {
674 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
675 }
676 CFRelease(newDict);
677 CFRelease(path);
678 }
679
680 if (ok) {
681 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
682 for (i = 0; i < n; i++) {
683 SCNetworkInterfaceRef member;
684 SCNetworkInterfacePrivateRef newMember;
685
686 member = CFArrayGetValueAtIndex(members, i);
687 newMember = __SCNetworkInterfaceCreateCopy(NULL,
688 member,
689 interfacePrivate->prefs,
690 interfacePrivate->serviceID);
691 CFArrayAppendValue(newMembers, newMember);
692 CFRelease(newMember);
693 }
694 CFRelease(interfacePrivate->bridge.interfaces);
695 interfacePrivate->bridge.interfaces = newMembers;
696 }
697
698 return ok;
699 }
700
701
702 Boolean
703 SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members)
704 {
705 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
706 Boolean ok;
707 int sc_status = kSCStatusOK;
708
709 if (!isA_SCBridgeInterface(bridge)) {
710 _SCErrorSet(kSCStatusInvalidArgument);
711 return FALSE;
712 }
713
714 if ((members != NULL) && !isA_CFArray(members)) {
715 _SCErrorSet(kSCStatusInvalidArgument);
716 return FALSE;
717 }
718
719 if (interfacePrivate->prefs != NULL) {
720 CFArrayRef available;
721 CFArrayRef current;
722 CFIndex i;
723 CFIndex n_available;
724 CFIndex n_current;
725 CFIndex n_members;
726 CFArrayRef services = NULL;
727
728 current = SCBridgeInterfaceGetMemberInterfaces(bridge);
729 n_current = (current != NULL) ? CFArrayGetCount(current) : 0;
730
731 available = SCBridgeInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs);
732 n_available = (available != NULL) ? CFArrayGetCount(available) : 0;
733
734 n_members = (members != NULL) ? CFArrayGetCount(members) : 0;
735 for (i = 0; i < n_members; i++) {
736 SCNetworkInterfaceRef member;
737
738 member = CFArrayGetValueAtIndex(members, i);
739
740 if ((current != NULL) &&
741 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) {
742 // current members are allowed
743 continue;
744 }
745
746 if ((available != NULL) &&
747 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) {
748 // available members are allowed but cannot be associated
749 // with any other network services.
750
751 if (services == NULL) {
752 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs);
753 }
754 if ((services != NULL) &&
755 __SCNetworkServiceExistsForInterface(services, member)) {
756 sc_status = kSCStatusKeyExists;
757 break;
758 }
759
760 // if available
761 continue;
762 }
763
764 // if member not allowed
765 sc_status = kSCStatusInvalidArgument;
766 break;
767 }
768
769 if (available != NULL) CFRelease(available);
770 if (services != NULL) CFRelease(services);
771 }
772
773 if (sc_status != kSCStatusOK) {
774 _SCErrorSet(sc_status);
775 return FALSE;
776 }
777
778 ok = __SCBridgeInterfaceSetMemberInterfaces(bridge, members);
779 return ok;
780 }
781
782
783 Boolean
784 SCBridgeInterfaceSetLocalizedDisplayName(SCBridgeInterfaceRef bridge, CFStringRef newName)
785 {
786 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
787 Boolean ok = TRUE;
788
789 if (!isA_SCBridgeInterface(bridge)) {
790 _SCErrorSet(kSCStatusInvalidArgument);
791 return FALSE;
792 }
793
794 if ((newName != NULL) && !isA_CFString(newName)) {
795 _SCErrorSet(kSCStatusInvalidArgument);
796 return FALSE;
797 }
798
799 // set name in the stored preferences
800 if (interfacePrivate->prefs != NULL) {
801 CFDictionaryRef dict;
802 CFMutableDictionaryRef newDict;
803 CFStringRef path;
804
805 path = CFStringCreateWithFormat(NULL,
806 NULL,
807 CFSTR("/%@/%@/%@"),
808 kSCPrefVirtualNetworkInterfaces,
809 kSCNetworkInterfaceTypeBridge,
810 interfacePrivate->entity_device);
811 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
812 if (!isA_CFDictionary(dict)) {
813 // if the prefs are confused
814 CFRelease(path);
815 _SCErrorSet(kSCStatusFailed);
816 return FALSE;
817 }
818
819 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
820 if (newName != NULL) {
821 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
822 } else {
823 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
824 }
825 if (!CFEqual(dict, newDict)) {
826 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
827 }
828 CFRelease(newDict);
829 CFRelease(path);
830 }
831
832 // set name in the SCBridgeInterfaceRef
833 if (ok) {
834 if (interfacePrivate->localized_name != NULL) {
835 CFRelease(interfacePrivate->localized_name);
836 interfacePrivate->localized_name = NULL;
837 }
838 if (newName != NULL) {
839 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
840 }
841 }
842
843 return ok;
844 }
845
846
847 Boolean
848 SCBridgeInterfaceSetOptions(SCBridgeInterfaceRef bridge, CFDictionaryRef newOptions)
849 {
850 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
851 Boolean ok = TRUE;
852
853 if (!isA_SCBridgeInterface(bridge)) {
854 _SCErrorSet(kSCStatusInvalidArgument);
855 return FALSE;
856 }
857
858 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
859 _SCErrorSet(kSCStatusInvalidArgument);
860 return FALSE;
861 }
862
863 // set options in the stored preferences
864 if (interfacePrivate->prefs != NULL) {
865 CFDictionaryRef dict;
866 CFMutableDictionaryRef newDict;
867 CFStringRef path;
868
869 path = CFStringCreateWithFormat(NULL,
870 NULL,
871 CFSTR("/%@/%@/%@"),
872 kSCPrefVirtualNetworkInterfaces,
873 kSCNetworkInterfaceTypeBridge,
874 interfacePrivate->entity_device);
875 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
876 if (!isA_CFDictionary(dict)) {
877 // if the prefs are confused
878 CFRelease(path);
879 _SCErrorSet(kSCStatusFailed);
880 return FALSE;
881 }
882
883 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
884 if (newOptions != NULL) {
885 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions, newOptions);
886 } else {
887 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions);
888 }
889 if (!CFEqual(dict, newDict)) {
890 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
891 }
892 CFRelease(newDict);
893 CFRelease(path);
894 }
895
896 // set options in the SCBridgeInterfaceRef
897 if (ok) {
898 if (interfacePrivate->bridge.options != NULL) {
899 CFRelease(interfacePrivate->bridge.options);
900 interfacePrivate->bridge.options = NULL;
901 }
902 if (newOptions != NULL) {
903 CFStringRef name_auto = NULL;
904
905 interfacePrivate->bridge.options = CFDictionaryCreateCopy(NULL, newOptions);
906
907 // set [auto] display name from options
908 if ((interfacePrivate->localized_name == NULL) &&
909 CFDictionaryGetValueIfPresent(newOptions,
910 CFSTR("__AUTO__"),
911 (const void **)&name_auto) &&
912 isA_CFString(name_auto)) {
913 // set display name
914 interfacePrivate->localized_key = name_auto;
915 if (interfacePrivate->localized_arg1 != NULL) {
916 CFRelease(interfacePrivate->localized_arg1);
917 interfacePrivate->localized_arg1 = NULL;
918 }
919 }
920 }
921 }
922
923 return ok;
924 }
925
926
927 #pragma mark -
928 #pragma mark SCBridgeInterface management
929
930
931 #ifdef IFT_BRIDGE
932 static Boolean
933 __bridge_add_interface(int s, CFStringRef bridge_if, CFStringRef interface_if)
934 {
935 struct ifbreq breq;
936 struct ifdrv ifd;
937
938 // bridge interface
939 bzero(&ifd, sizeof(ifd));
940 (void) _SC_cfstring_to_cstring(bridge_if,
941 ifd.ifd_name,
942 sizeof(ifd.ifd_name),
943 kCFStringEncodingASCII);
944 ifd.ifd_cmd = BRDGADD;
945 ifd.ifd_len = sizeof(breq);
946 ifd.ifd_data = (caddr_t)&breq;
947
948 // new bridge member
949 bzero(&breq, sizeof(breq));
950 (void) _SC_cfstring_to_cstring(interface_if,
951 breq.ifbr_ifsname,
952 sizeof(breq.ifbr_ifsname),
953 kCFStringEncodingASCII);
954
955 // add new bridge member
956 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) {
957 _SCErrorSet(errno);
958 SCLog(TRUE, LOG_ERR,
959 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"),
960 interface_if,
961 bridge_if,
962 strerror(errno));
963 return FALSE;
964 }
965
966 return TRUE;
967 }
968
969
970 static Boolean
971 __bridge_remove_interface(int s, CFStringRef bridge_if, CFStringRef interface_if)
972 {
973 struct ifbreq breq;
974 struct ifdrv ifd;
975
976 // bridge interface
977 bzero(&ifd, sizeof(ifd));
978 (void) _SC_cfstring_to_cstring(bridge_if,
979 ifd.ifd_name,
980 sizeof(ifd.ifd_name),
981 kCFStringEncodingASCII);
982 ifd.ifd_cmd = BRDGDEL;
983 ifd.ifd_len = sizeof(breq);
984 ifd.ifd_data = (caddr_t)&breq;
985
986 // bridge member to remove
987 bzero(&breq, sizeof(breq));
988 (void) _SC_cfstring_to_cstring(interface_if,
989 breq.ifbr_ifsname,
990 sizeof(breq.ifbr_ifsname),
991 kCFStringEncodingASCII);
992
993 // remove bridge member
994 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) {
995 _SCErrorSet(errno);
996 SCLog(TRUE, LOG_ERR,
997 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"),
998 interface_if,
999 bridge_if,
1000 strerror(errno));
1001 return FALSE;
1002 }
1003
1004 return TRUE;
1005 }
1006 #endif // IFT_BRIDGE
1007
1008
1009 Boolean
1010 _SCBridgeInterfaceUpdateConfiguration(SCPreferencesRef prefs)
1011 {
1012 #ifdef IFT_BRIDGE
1013 CFArrayRef active = NULL;
1014 CFArrayRef config = NULL;
1015 CFIndex i;
1016 CFIndex nActive;
1017 CFIndex nConfig;
1018 Boolean ok = TRUE;
1019 int s = -1;
1020
1021 if (prefs == NULL) {
1022 _SCErrorSet(kSCStatusInvalidArgument);
1023 return FALSE;
1024 }
1025
1026 /* configured Bridges */
1027 config = SCBridgeInterfaceCopyAll(prefs);
1028 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
1029
1030 /* active Bridges */
1031 active = _SCBridgeInterfaceCopyActive();
1032 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
1033
1034 /*
1035 * remove any no-longer-configured bridge interfaces and
1036 * any devices associated with a bridge that are no longer
1037 * associated with a bridge.
1038 */
1039 for (i = 0; i < nActive; i++) {
1040 SCBridgeInterfaceRef a_bridge;
1041 CFStringRef a_bridge_if;
1042 CFIndex j;
1043 Boolean found = FALSE;
1044
1045 a_bridge = CFArrayGetValueAtIndex(active, i);
1046 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge);
1047
1048 for (j = 0; j < nConfig; j++) {
1049 SCBridgeInterfaceRef c_bridge;
1050 CFStringRef c_bridge_if;
1051
1052 c_bridge = CFArrayGetValueAtIndex(config, j);
1053 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge);
1054
1055 if (CFEqual(a_bridge_if, c_bridge_if)) {
1056 CFIndex a;
1057 CFArrayRef a_bridge_interfaces;
1058 CFIndex a_count;
1059 CFArrayRef c_bridge_interfaces;
1060 CFIndex c_count;
1061
1062 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge);
1063 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0;
1064
1065 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge);
1066 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0;
1067
1068 for (a = 0; a < a_count; a++) {
1069 SCNetworkInterfaceRef a_interface;
1070 CFStringRef a_interface_if;
1071
1072 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a);
1073 if ((c_count == 0) ||
1074 !CFArrayContainsValue(c_bridge_interfaces,
1075 CFRangeMake(0, c_count),
1076 a_interface)) {
1077 /*
1078 * if this device is no longer part
1079 * of the bridge.
1080 */
1081 if (s == -1) {
1082 s = inet_dgram_socket();
1083 if (s == -1) {
1084 _SCErrorSet(errno);
1085 ok = FALSE;
1086 goto done;
1087 }
1088 }
1089
1090 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1091 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) {
1092 ok = FALSE;
1093 }
1094 }
1095 }
1096
1097 found = TRUE;
1098 break;
1099 }
1100 }
1101
1102 if (!found) {
1103 /*
1104 * if this interface is no longer configured
1105 */
1106 if (s == -1) {
1107 s = inet_dgram_socket();
1108 if (s == -1) {
1109 _SCErrorSet(errno);
1110 ok = FALSE;
1111 goto done;
1112 }
1113 }
1114
1115 if (!__destroyInterface(s, a_bridge_if)) {
1116 _SCErrorSet(errno);
1117 ok = FALSE;
1118 }
1119 }
1120 }
1121
1122 /*
1123 * add any newly-configured bridge interfaces and add any
1124 * devices that should now be associated with the bridge.
1125 */
1126 for (i = 0; i < nConfig; i++) {
1127 SCBridgeInterfaceRef c_bridge;
1128 CFArrayRef c_bridge_interfaces;
1129 CFStringRef c_bridge_if;
1130 CFIndex c_count;
1131 Boolean found = FALSE;
1132 CFIndex j;
1133
1134 c_bridge = CFArrayGetValueAtIndex(config, i);
1135 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge);
1136 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge);
1137 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0;
1138
1139 for (j = 0; j < nActive; j++) {
1140 SCBridgeInterfaceRef a_bridge;
1141 CFArrayRef a_bridge_interfaces;
1142 CFStringRef a_bridge_if;
1143 CFIndex a_count;
1144
1145 a_bridge = CFArrayGetValueAtIndex(active, j);
1146 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge);
1147 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge);
1148 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0;
1149
1150 if (CFEqual(c_bridge_if, a_bridge_if)) {
1151 CFIndex c;
1152 Boolean if_list_change = FALSE;
1153
1154 found = TRUE;
1155
1156 if (!_SC_CFEqual(c_bridge_interfaces, a_bridge_interfaces)) {
1157 if_list_change = TRUE;
1158 }
1159 if (!if_list_change) {
1160 break; // if no change
1161 }
1162 if (s == -1) {
1163 s = inet_dgram_socket();
1164 if (s == -1) {
1165 _SCErrorSet(errno);
1166 ok = FALSE;
1167 goto done;
1168 }
1169 }
1170 if (!if_list_change) {
1171 break; // no if list changes
1172 }
1173
1174 /*
1175 * ensure that the first device of the bridge matches, if
1176 * not then we remove all current devices and add them
1177 * back in the preferred order.
1178 */
1179 if ((c_count > 0) &&
1180 (a_count > 0) &&
1181 !CFEqual(CFArrayGetValueAtIndex(c_bridge_interfaces, 0),
1182 CFArrayGetValueAtIndex(a_bridge_interfaces, 0))) {
1183 CFIndex a;
1184
1185 for (a = 0; a < a_count; a++) {
1186 SCNetworkInterfaceRef a_interface;
1187 CFStringRef a_interface_if;
1188
1189 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a);
1190 if (!CFArrayContainsValue(c_bridge_interfaces,
1191 CFRangeMake(0, c_count),
1192 a_interface)) {
1193 continue; // if already removed
1194 }
1195
1196 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1197 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) {
1198 ok = FALSE;
1199 }
1200 }
1201
1202 a_count = 0; // all active devices have been removed
1203 }
1204
1205 /*
1206 * add any devices which are not currently associated
1207 * with the bridge interface.
1208 */
1209 for (c = 0; c < c_count; c++) {
1210 SCNetworkInterfaceRef c_interface;
1211 SCNetworkInterfacePrivateRef c_interfacePrivate;
1212 CFStringRef c_interface_if;
1213
1214 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c);
1215 if ((a_count == 0) ||
1216 !CFArrayContainsValue(a_bridge_interfaces,
1217 CFRangeMake(0, a_count),
1218 c_interface)) {
1219 /*
1220 * check if this member interface can be added to a bridge.
1221 */
1222 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1223 if (!c_interfacePrivate->supportsBridge) {
1224 // if member not supported
1225 continue;
1226 }
1227
1228 /*
1229 * if this member interface is not currently part of the bridge.
1230 */
1231 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1232 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) {
1233 // if member could not be added
1234 ok = FALSE;
1235 }
1236 }
1237 }
1238
1239 break;
1240 }
1241 }
1242
1243 if (!found) {
1244 CFIndex c;
1245
1246 if (s == -1) {
1247 s = inet_dgram_socket();
1248 if (s == -1) {
1249 _SCErrorSet(errno);
1250 ok = FALSE;
1251 goto done;
1252 }
1253 }
1254
1255 /*
1256 * establish the new bridge interface.
1257 */
1258 if (!__createInterface(s, c_bridge_if)) {
1259 _SCErrorSet(errno);
1260 ok = FALSE;
1261 continue;
1262 }
1263
1264 /*
1265 * add the member interfaces
1266 */
1267 for (c = 0; c < c_count; c++) {
1268 SCNetworkInterfaceRef c_interface;
1269 SCNetworkInterfacePrivateRef c_interfacePrivate;
1270 CFStringRef c_interface_if;
1271
1272 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c);
1273 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1274 if (!c_interfacePrivate->supportsBridge) {
1275 // if member not supported
1276 continue;
1277 }
1278
1279 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1280 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) {
1281 // if member could not be added
1282 ok = FALSE;
1283 }
1284 }
1285 }
1286
1287 }
1288
1289 done :
1290
1291 if (active != NULL) CFRelease(active);
1292 if (config != NULL) CFRelease(config);
1293 if (s != -1) (void) close(s);
1294
1295 return ok;
1296 #else // IFT_BRIDGE
1297 return TRUE;
1298 #endif // IFT_BRIDGE
1299 }