]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/BridgeConfiguration.c
configd-453.16.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / BridgeConfiguration.c
1 /*
2 * Copyright (c) 2009-2011 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 CFIndex n;
168
169 // create the bridge interface
170 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if);
171
172 // add member interfaces
173 interfaces = CFDictionaryGetValue(bridge_info, kSCPropVirtualNetworkInterfacesBridgeInterfaces);
174 n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0;
175 for (i = 0; i < n; i++) {
176 CFStringRef member;
177
178 member = CFArrayGetValueAtIndex(interfaces, i);
179 if (isA_CFString(member)) {
180 add_interface(&members, member);
181 }
182 }
183 if (members != NULL) {
184 _SCBridgeInterfaceSetMemberInterfaces(bridge, members);
185 CFRelease(members);
186 }
187
188 // set display name
189 name = CFDictionaryGetValue(bridge_info, kSCPropUserDefinedName);
190 if (isA_CFString(name)) {
191 SCBridgeInterfaceSetLocalizedDisplayName(bridge, name);
192 }
193
194 // set options
195 bridge_options = CFDictionaryGetValue(bridge_info, kSCPropVirtualNetworkInterfacesBridgeOptions);
196 if (isA_CFDictionary(bridge_options)) {
197 SCBridgeInterfaceSetOptions(bridge, bridge_options);
198 }
199
200 // estabish link to the stored configuration
201 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
202 interfacePrivate->prefs = CFRetain(myContext->prefs);
203
204 CFArrayAppendValue(myContext->bridges, bridge);
205 CFRelease(bridge);
206
207 return;
208 }
209
210
211 #pragma mark -
212 #pragma mark SCBridgeInterface APIs
213
214
215 CFArrayRef
216 SCBridgeInterfaceCopyAll(SCPreferencesRef prefs)
217 {
218 addContext context;
219 CFDictionaryRef dict;
220 CFStringRef path;
221
222 context.bridges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
223 context.prefs = prefs;
224
225 path = CFStringCreateWithFormat(NULL,
226 NULL,
227 CFSTR("/%@/%@"),
228 kSCPrefVirtualNetworkInterfaces,
229 kSCNetworkInterfaceTypeBridge);
230 dict = SCPreferencesPathGetValue(prefs, path);
231 if (isA_CFDictionary(dict)) {
232 CFDictionaryApplyFunction(dict, add_configured_interface, &context);
233 }
234 CFRelease(path);
235
236 return context.bridges;
237 }
238
239
240 __private_extern__ void
241 __SCBridgeInterfaceListCollectMembers(CFArrayRef interfaces, CFMutableSetRef set)
242 {
243 CFIndex i;
244 CFIndex n;
245
246 n = CFArrayGetCount(interfaces);
247 for (i = 0; i < n; i++) {
248 SCBridgeInterfaceRef bridgeInterface;
249 CFArrayRef members;
250
251 bridgeInterface = CFArrayGetValueAtIndex(interfaces, i);
252 members = SCBridgeInterfaceGetMemberInterfaces(bridgeInterface);
253 if (members != NULL) {
254 CFIndex j;
255 CFIndex n_members;
256
257 // exclude the member interfaces of this bridge
258 n_members = CFArrayGetCount(members);
259 for (j = 0; j < n_members; j++) {
260 SCNetworkInterfaceRef member;
261
262 member = CFArrayGetValueAtIndex(members, j);
263 CFSetAddValue(set, member);
264 }
265 }
266
267 }
268 return;
269 }
270
271
272 CFArrayRef /* of SCNetworkInterfaceRef's */
273 SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs)
274 {
275 CFMutableArrayRef available;
276 CFMutableSetRef excluded;
277 CFArrayRef interfaces;
278
279 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
280 excluded = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks);
281
282 #if !TARGET_OS_IPHONE
283 // exclude Bond [member] interfaces
284 interfaces = SCBondInterfaceCopyAll(prefs);
285 if (interfaces != NULL) {
286 __SCBondInterfaceListCollectMembers(interfaces, excluded);
287 CFRelease(interfaces);
288 }
289 #endif // !TARGET_OS_IPHONE
290
291 // exclude Bridge [member] interfaces
292 interfaces = SCBridgeInterfaceCopyAll(prefs);
293 if (interfaces != NULL) {
294 __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
295 CFRelease(interfaces);
296 }
297
298 // exclude VLAN [physical] interfaces
299 interfaces = SCVLANInterfaceCopyAll(prefs);
300 if (interfaces != NULL) {
301 CFIndex i;
302 CFIndex n;
303
304 n = CFArrayGetCount(interfaces);
305 for (i = 0; i < n; i++) {
306 SCVLANInterfaceRef vlanInterface;
307 SCNetworkInterfaceRef physical;
308
309 // exclude the physical interface of this VLAN
310 vlanInterface = CFArrayGetValueAtIndex(interfaces, i);
311 physical = SCVLANInterfaceGetPhysicalInterface(vlanInterface);
312 CFSetAddValue(excluded, physical);
313 }
314 CFRelease(interfaces);
315 }
316
317 // identify available interfaces
318 interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface();
319 if (interfaces != NULL) {
320 CFIndex i;
321 CFIndex n;
322
323 n = CFArrayGetCount(interfaces);
324 for (i = 0; i < n; i++) {
325 SCNetworkInterfaceRef interface;
326 SCNetworkInterfacePrivateRef interfacePrivate;
327
328 interface = CFArrayGetValueAtIndex(interfaces, i);
329 interfacePrivate = (SCNetworkInterfacePrivateRef)interface;
330
331 if (!interfacePrivate->supportsBridge) {
332 // if this interface is not available
333 continue;
334 }
335
336 if (CFSetContainsValue(excluded, interface)) {
337 // if excluded
338 continue;
339 }
340
341 CFArrayAppendValue(available, interface);
342 }
343 CFRelease(interfaces);
344 }
345
346 CFRelease(excluded);
347
348 return available;
349 }
350
351
352 CFArrayRef
353 _SCBridgeInterfaceCopyActive(void)
354 {
355 struct ifaddrs *ifap;
356 struct ifaddrs *ifp;
357 int s;
358 CFMutableArrayRef bridges = NULL;
359
360 if (getifaddrs(&ifap) == -1) {
361 _SCErrorSet(errno);
362 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
363 return NULL;
364 }
365
366 s = inet_dgram_socket();
367 if (s == -1) {
368 _SCErrorSet(errno);
369 goto done;
370 }
371
372 bridges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
373
374 for (ifp = ifap; ifp != NULL; ifp = ifp->ifa_next) {
375 #ifdef IFT_BRIDGE
376 SCBridgeInterfaceRef bridge;
377 CFStringRef bridge_if;
378 struct ifbifconf *ibc_p;
379 struct if_data *if_data;
380 CFMutableArrayRef members = NULL;
381
382 if_data = (struct if_data *)ifp->ifa_data;
383 if (if_data == NULL
384 || ifp->ifa_addr->sa_family != AF_LINK
385 || if_data->ifi_type != IFT_BRIDGE) {
386 continue;
387 }
388
389 ibc_p = ifbifconf_copy(s, ifp->ifa_name);
390 if (ibc_p == NULL) {
391 if (errno == EBUSY) {
392 continue;
393 }
394 _SCErrorSet(errno);
395 SCLog(TRUE, LOG_ERR,
396 CFSTR("ifbifconf_copy(%s) failed: %s"),
397 ifp->ifa_name,
398 strerror(errno));
399 CFRelease(bridges);
400 bridges = NULL;
401 goto done;
402 }
403
404 // create the bridge interface
405 bridge_if = CFStringCreateWithCString(NULL, ifp->ifa_name, kCFStringEncodingASCII);
406 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(NULL, bridge_if);
407 CFRelease(bridge_if);
408
409 // add member interfaces
410 if (ibc_p->ifbic_len > 0) {
411 int i;
412
413 // iterate over each member interface
414 for (i = 0; i < ibc_p->ifbic_len / sizeof(struct ifbreq); i++) {
415 struct ifbreq *ibr_p;
416 CFStringRef member;
417
418 ibr_p = ibc_p->ifbic_req + i;
419 member = CFStringCreateWithCString(NULL, ibr_p->ifbr_ifsname, kCFStringEncodingASCII);
420 add_interface(&members, member);
421 CFRelease(member);
422 }
423 }
424 free(ibc_p);
425
426 if (members != NULL) {
427 _SCBridgeInterfaceSetMemberInterfaces(bridge, members);
428 CFRelease(members);
429 }
430
431 // add bridge
432 CFArrayAppendValue(bridges, bridge);
433 CFRelease(bridge);
434 #endif // IFT_BRIDGE
435 }
436
437 done :
438
439 (void) close(s);
440 freeifaddrs(ifap);
441 return bridges;
442 }
443
444
445 SCBridgeInterfaceRef
446 SCBridgeInterfaceCreate(SCPreferencesRef prefs)
447 {
448 CFAllocatorRef allocator;
449 SCBridgeInterfaceRef bridge = NULL;
450 CFIndex i;
451
452 if (prefs == NULL) {
453 _SCErrorSet(kSCStatusInvalidArgument);
454 return NULL;
455 }
456
457 allocator = CFGetAllocator(prefs);
458
459 // create a new bridge using an unused interface name
460 for (i = 0; bridge == NULL; i++) {
461 CFDictionaryRef dict;
462 CFStringRef bridge_if;
463 SCNetworkInterfacePrivateRef interfacePrivate;
464 CFMutableDictionaryRef newDict;
465 CFArrayRef newInterfaces;
466 Boolean ok;
467 CFStringRef path;
468
469 bridge_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("bridge%d"), i);
470 path = CFStringCreateWithFormat(allocator,
471 NULL,
472 CFSTR("/%@/%@/%@"),
473 kSCPrefVirtualNetworkInterfaces,
474 kSCNetworkInterfaceTypeBridge,
475 bridge_if);
476 dict = SCPreferencesPathGetValue(prefs, path);
477 if (dict != NULL) {
478 // if bridge interface name not available
479 CFRelease(path);
480 CFRelease(bridge_if);
481 continue;
482 }
483
484 // add the bridge to the stored preferences
485 newDict = CFDictionaryCreateMutable(allocator,
486 0,
487 &kCFTypeDictionaryKeyCallBacks,
488 &kCFTypeDictionaryValueCallBacks);
489 newInterfaces = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks);
490 CFDictionaryAddValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newInterfaces);
491 CFRelease(newInterfaces);
492 ok = SCPreferencesPathSetValue(prefs, path, newDict);
493 CFRelease(newDict);
494 CFRelease(path);
495 if (!ok) {
496 // if the bridge could not be saved
497 CFRelease(bridge_if);
498 break;
499 }
500
501 // create the SCBridgeInterfaceRef
502 bridge = (SCBridgeInterfaceRef)_SCBridgeInterfaceCreatePrivate(allocator, bridge_if);
503 CFRelease(bridge_if);
504
505 // estabish link to the stored configuration
506 interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
507 interfacePrivate->prefs = CFRetain(prefs);
508 }
509
510 return bridge;
511 }
512
513
514 Boolean
515 SCBridgeInterfaceRemove(SCBridgeInterfaceRef bridge)
516 {
517 CFStringRef bridge_if;
518 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
519 Boolean ok;
520 CFStringRef path;
521
522 if (!isA_SCBridgeInterface(bridge)) {
523 _SCErrorSet(kSCStatusInvalidArgument);
524 return FALSE;
525 }
526
527 if (interfacePrivate->prefs == NULL) {
528 _SCErrorSet(kSCStatusInvalidArgument);
529 return FALSE;
530 }
531
532 bridge_if = SCNetworkInterfaceGetBSDName(bridge);
533 path = CFStringCreateWithFormat(NULL,
534 NULL,
535 CFSTR("/%@/%@/%@"),
536 kSCPrefVirtualNetworkInterfaces,
537 kSCNetworkInterfaceTypeBridge,
538 bridge_if);
539 ok = SCPreferencesPathRemoveValue(interfacePrivate->prefs, path);
540 CFRelease(path);
541
542 return ok;
543 }
544
545
546 CFArrayRef
547 SCBridgeInterfaceGetMemberInterfaces(SCBridgeInterfaceRef bridge)
548 {
549 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
550
551 if (!isA_SCBridgeInterface(bridge)) {
552 _SCErrorSet(kSCStatusInvalidArgument);
553 return NULL;
554 }
555
556 return interfacePrivate->bridge.interfaces;
557 }
558
559
560 CFDictionaryRef
561 SCBridgeInterfaceGetOptions(SCBridgeInterfaceRef bridge)
562 {
563 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
564
565 if (!isA_SCBridgeInterface(bridge)) {
566 _SCErrorSet(kSCStatusInvalidArgument);
567 return NULL;
568 }
569
570 return interfacePrivate->bridge.options;
571 }
572
573
574 static Boolean
575 _SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members)
576 {
577 CFIndex i;
578 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
579 CFIndex n;
580 CFMutableArrayRef newMembers;
581 Boolean ok = TRUE;
582
583 n = (members != NULL) ? CFArrayGetCount(members) : 0;
584
585 // set member interfaces in the stored preferences
586 if (interfacePrivate->prefs != NULL) {
587 CFDictionaryRef dict;
588 CFMutableDictionaryRef newDict;
589 CFStringRef path;
590
591 path = CFStringCreateWithFormat(NULL,
592 NULL,
593 CFSTR("/%@/%@/%@"),
594 kSCPrefVirtualNetworkInterfaces,
595 kSCNetworkInterfaceTypeBridge,
596 interfacePrivate->entity_device);
597 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
598 if (!isA_CFDictionary(dict)) {
599 // if the prefs are confused
600 CFRelease(path);
601 _SCErrorSet(kSCStatusFailed);
602 return FALSE;
603 }
604
605 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
606 for (i = 0; i < n; i++) {
607 SCNetworkInterfaceRef interface;
608 CFStringRef memberName;
609
610 interface = CFArrayGetValueAtIndex(members, i);
611 memberName = SCNetworkInterfaceGetBSDName(interface);
612 CFArrayAppendValue(newMembers, memberName);
613 }
614
615 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
616 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeInterfaces, newMembers);
617 CFRelease(newMembers);
618
619 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
620 CFRelease(newDict);
621 CFRelease(path);
622 }
623
624 if (ok) {
625 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
626 for (i = 0; i < n; i++) {
627 SCNetworkInterfaceRef member;
628 SCNetworkInterfacePrivateRef newMember;
629
630 member = CFArrayGetValueAtIndex(members, i);
631 newMember = __SCNetworkInterfaceCreateCopy(NULL,
632 member,
633 interfacePrivate->prefs,
634 interfacePrivate->serviceID);
635 CFArrayAppendValue(newMembers, newMember);
636 CFRelease(newMember);
637 }
638 CFRelease(interfacePrivate->bridge.interfaces);
639 interfacePrivate->bridge.interfaces = newMembers;
640 }
641
642 return ok;
643 }
644
645
646 Boolean
647 SCBridgeInterfaceSetMemberInterfaces(SCBridgeInterfaceRef bridge, CFArrayRef members)
648 {
649 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
650 Boolean ok;
651 int sc_status = kSCStatusOK;
652
653 if (!isA_SCBridgeInterface(bridge)) {
654 _SCErrorSet(kSCStatusInvalidArgument);
655 return FALSE;
656 }
657
658 if ((members != NULL) && !isA_CFArray(members)) {
659 _SCErrorSet(kSCStatusInvalidArgument);
660 return FALSE;
661 }
662
663 if (interfacePrivate->prefs != NULL) {
664 CFArrayRef available;
665 CFArrayRef current;
666 CFIndex i;
667 CFIndex n_available;
668 CFIndex n_current;
669 CFIndex n_members;
670 CFArrayRef services = NULL;
671
672 current = SCBridgeInterfaceGetMemberInterfaces(bridge);
673 n_current = (current != NULL) ? CFArrayGetCount(current) : 0;
674
675 available = SCBridgeInterfaceCopyAvailableMemberInterfaces(interfacePrivate->prefs);
676 n_available = (available != NULL) ? CFArrayGetCount(available) : 0;
677
678 n_members = (members != NULL) ? CFArrayGetCount(members) : 0;
679 for (i = 0; i < n_members; i++) {
680 SCNetworkInterfaceRef member;
681
682 member = CFArrayGetValueAtIndex(members, i);
683
684 if ((current != NULL) &&
685 CFArrayContainsValue(current, CFRangeMake(0, n_current), member)) {
686 // current members are allowed
687 continue;
688 }
689
690 if ((available != NULL) &&
691 CFArrayContainsValue(available, CFRangeMake(0, n_available), member)) {
692 // available members are allowed but cannot be associated
693 // with any other network services.
694
695 if (services == NULL) {
696 services = __SCNetworkServiceCopyAllEnabled(interfacePrivate->prefs);
697 }
698 if ((services != NULL) &&
699 __SCNetworkServiceExistsForInterface(services, member)) {
700 sc_status = kSCStatusKeyExists;
701 break;
702 }
703
704 // if available
705 continue;
706 }
707
708 // if member not allowed
709 sc_status = kSCStatusInvalidArgument;
710 break;
711 }
712
713 if (available != NULL) CFRelease(available);
714 if (services != NULL) CFRelease(services);
715 }
716
717 if (sc_status != kSCStatusOK) {
718 _SCErrorSet(sc_status);
719 return FALSE;
720 }
721
722 ok = _SCBridgeInterfaceSetMemberInterfaces(bridge, members);
723 return ok;
724 }
725
726
727 Boolean
728 SCBridgeInterfaceSetLocalizedDisplayName(SCBridgeInterfaceRef bridge, CFStringRef newName)
729 {
730 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
731 Boolean ok = TRUE;
732
733 if (!isA_SCBridgeInterface(bridge)) {
734 _SCErrorSet(kSCStatusInvalidArgument);
735 return FALSE;
736 }
737
738 if ((newName != NULL) && !isA_CFString(newName)) {
739 _SCErrorSet(kSCStatusInvalidArgument);
740 return FALSE;
741 }
742
743 // set name in the stored preferences
744 if (interfacePrivate->prefs != NULL) {
745 CFDictionaryRef dict;
746 CFMutableDictionaryRef newDict;
747 CFStringRef path;
748
749 path = CFStringCreateWithFormat(NULL,
750 NULL,
751 CFSTR("/%@/%@/%@"),
752 kSCPrefVirtualNetworkInterfaces,
753 kSCNetworkInterfaceTypeBridge,
754 interfacePrivate->entity_device);
755 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
756 if (!isA_CFDictionary(dict)) {
757 // if the prefs are confused
758 CFRelease(path);
759 _SCErrorSet(kSCStatusFailed);
760 return FALSE;
761 }
762
763 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
764 if (newName != NULL) {
765 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
766 } else {
767 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
768 }
769 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
770 CFRelease(newDict);
771 CFRelease(path);
772 }
773
774 // set name in the SCBridgeInterfaceRef
775 if (ok) {
776 if (interfacePrivate->localized_name != NULL) {
777 CFRelease(interfacePrivate->localized_name);
778 interfacePrivate->localized_name = NULL;
779 }
780 if (newName != NULL) {
781 interfacePrivate->localized_name = CFStringCreateCopy(NULL, newName);
782 }
783 }
784
785 return ok;
786 }
787
788
789 Boolean
790 SCBridgeInterfaceSetOptions(SCBridgeInterfaceRef bridge, CFDictionaryRef newOptions)
791 {
792 SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)bridge;
793 Boolean ok = TRUE;
794
795 if (!isA_SCBridgeInterface(bridge)) {
796 _SCErrorSet(kSCStatusInvalidArgument);
797 return FALSE;
798 }
799
800 if ((newOptions != NULL) && !isA_CFDictionary(newOptions)) {
801 _SCErrorSet(kSCStatusInvalidArgument);
802 return FALSE;
803 }
804
805 // set options in the stored preferences
806 if (interfacePrivate->prefs != NULL) {
807 CFDictionaryRef dict;
808 CFMutableDictionaryRef newDict;
809 CFStringRef path;
810
811 path = CFStringCreateWithFormat(NULL,
812 NULL,
813 CFSTR("/%@/%@/%@"),
814 kSCPrefVirtualNetworkInterfaces,
815 kSCNetworkInterfaceTypeBridge,
816 interfacePrivate->entity_device);
817 dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path);
818 if (!isA_CFDictionary(dict)) {
819 // if the prefs are confused
820 CFRelease(path);
821 _SCErrorSet(kSCStatusFailed);
822 return FALSE;
823 }
824
825 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
826 if (newOptions != NULL) {
827 CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions, newOptions);
828 } else {
829 CFDictionaryRemoveValue(newDict, kSCPropVirtualNetworkInterfacesBridgeOptions);
830 }
831 ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict);
832 CFRelease(newDict);
833 CFRelease(path);
834 }
835
836 // set options in the SCBridgeInterfaceRef
837 if (ok) {
838 if (interfacePrivate->bridge.options != NULL) {
839 CFRelease(interfacePrivate->bridge.options);
840 interfacePrivate->bridge.options = NULL;
841 }
842 if (newOptions != NULL) {
843 interfacePrivate->bridge.options = CFDictionaryCreateCopy(NULL, newOptions);
844 }
845 }
846
847 return ok;
848 }
849
850
851 #pragma mark -
852 #pragma mark SCBridgeInterface management
853
854
855 #ifdef IFT_BRIDGE
856 static Boolean
857 __bridge_add_interface(int s, CFStringRef bridge_if, CFStringRef interface_if)
858 {
859 struct ifbreq breq;
860 struct ifdrv ifd;
861
862 // bridge interface
863 bzero(&ifd, sizeof(ifd));
864 (void) _SC_cfstring_to_cstring(bridge_if,
865 ifd.ifd_name,
866 sizeof(ifd.ifd_name),
867 kCFStringEncodingASCII);
868 ifd.ifd_cmd = BRDGADD;
869 ifd.ifd_len = sizeof(breq);
870 ifd.ifd_data = (caddr_t)&breq;
871
872 // new bridge member
873 bzero(&breq, sizeof(breq));
874 (void) _SC_cfstring_to_cstring(interface_if,
875 breq.ifbr_ifsname,
876 sizeof(breq.ifbr_ifsname),
877 kCFStringEncodingASCII);
878
879 // add new bridge member
880 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) {
881 _SCErrorSet(errno);
882 SCLog(TRUE, LOG_ERR,
883 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"),
884 interface_if,
885 bridge_if,
886 strerror(errno));
887 return FALSE;
888 }
889
890 return TRUE;
891 }
892
893
894 static Boolean
895 __bridge_remove_interface(int s, CFStringRef bridge_if, CFStringRef interface_if)
896 {
897 struct ifbreq breq;
898 struct ifdrv ifd;
899
900 // bridge interface
901 bzero(&ifd, sizeof(ifd));
902 (void) _SC_cfstring_to_cstring(bridge_if,
903 ifd.ifd_name,
904 sizeof(ifd.ifd_name),
905 kCFStringEncodingASCII);
906 ifd.ifd_cmd = BRDGDEL;
907 ifd.ifd_len = sizeof(breq);
908 ifd.ifd_data = (caddr_t)&breq;
909
910 // bridge member to remove
911 bzero(&breq, sizeof(breq));
912 (void) _SC_cfstring_to_cstring(interface_if,
913 breq.ifbr_ifsname,
914 sizeof(breq.ifbr_ifsname),
915 kCFStringEncodingASCII);
916
917 // remove bridge member
918 if (ioctl(s, SIOCSDRVSPEC, (caddr_t)&ifd) == -1) {
919 _SCErrorSet(errno);
920 SCLog(TRUE, LOG_ERR,
921 CFSTR("could not add interface \"%@\" to bridge \"%@\": %s"),
922 interface_if,
923 bridge_if,
924 strerror(errno));
925 return FALSE;
926 }
927
928 return TRUE;
929 }
930 #endif // IFT_BRIDGE
931
932
933 Boolean
934 _SCBridgeInterfaceUpdateConfiguration(SCPreferencesRef prefs)
935 {
936 #ifdef IFT_BRIDGE
937 CFArrayRef active = NULL;
938 CFArrayRef config = NULL;
939 CFIndex i;
940 CFIndex nActive;
941 CFIndex nConfig;
942 Boolean ok = TRUE;
943 int s = -1;
944
945 if (prefs == NULL) {
946 _SCErrorSet(kSCStatusInvalidArgument);
947 return FALSE;
948 }
949
950 /* configured Bridges */
951 config = SCBridgeInterfaceCopyAll(prefs);
952 nConfig = (config != NULL) ? CFArrayGetCount(config) : 0;
953
954 /* active Bridges */
955 active = _SCBridgeInterfaceCopyActive();
956 nActive = (active != NULL) ? CFArrayGetCount(active) : 0;
957
958 /*
959 * remove any no-longer-configured bridge interfaces and
960 * any devices associated with a bridge that are no longer
961 * associated with a bridge.
962 */
963 for (i = 0; i < nActive; i++) {
964 SCBridgeInterfaceRef a_bridge;
965 CFStringRef a_bridge_if;
966 CFIndex j;
967 Boolean found = FALSE;
968
969 a_bridge = CFArrayGetValueAtIndex(active, i);
970 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge);
971
972 for (j = 0; j < nConfig; j++) {
973 SCBridgeInterfaceRef c_bridge;
974 CFStringRef c_bridge_if;
975
976 c_bridge = CFArrayGetValueAtIndex(config, j);
977 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge);
978
979 if (CFEqual(a_bridge_if, c_bridge_if)) {
980 CFIndex a;
981 CFArrayRef a_bridge_interfaces;
982 CFIndex a_count;
983 CFArrayRef c_bridge_interfaces;
984 CFIndex c_count;
985
986 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge);
987 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0;
988
989 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge);
990 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0;
991
992 for (a = 0; a < a_count; a++) {
993 SCNetworkInterfaceRef a_interface;
994 CFStringRef a_interface_if;
995
996 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a);
997 if ((c_count == 0) ||
998 !CFArrayContainsValue(c_bridge_interfaces,
999 CFRangeMake(0, c_count),
1000 a_interface)) {
1001 /*
1002 * if this device is no longer part
1003 * of the bridge.
1004 */
1005 if (s == -1) {
1006 s = inet_dgram_socket();
1007 if (s == -1) {
1008 _SCErrorSet(errno);
1009 ok = FALSE;
1010 goto done;
1011 }
1012 }
1013
1014 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1015 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) {
1016 ok = FALSE;
1017 }
1018 }
1019 }
1020
1021 found = TRUE;
1022 break;
1023 }
1024 }
1025
1026 if (!found) {
1027 /*
1028 * if this interface is no longer configured
1029 */
1030 if (s == -1) {
1031 s = inet_dgram_socket();
1032 if (s == -1) {
1033 _SCErrorSet(errno);
1034 ok = FALSE;
1035 goto done;
1036 }
1037 }
1038
1039 if (!__destroyInterface(s, a_bridge_if)) {
1040 _SCErrorSet(errno);
1041 ok = FALSE;
1042 }
1043 }
1044 }
1045
1046 /*
1047 * add any newly-configured bridge interfaces and add any
1048 * devices that should now be associated with the bridge.
1049 */
1050 for (i = 0; i < nConfig; i++) {
1051 SCBridgeInterfaceRef c_bridge;
1052 CFArrayRef c_bridge_interfaces;
1053 CFStringRef c_bridge_if;
1054 CFIndex c_count;
1055 Boolean found = FALSE;
1056 CFIndex j;
1057
1058 c_bridge = CFArrayGetValueAtIndex(config, i);
1059 c_bridge_if = SCNetworkInterfaceGetBSDName(c_bridge);
1060 c_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(c_bridge);
1061 c_count = (c_bridge_interfaces != NULL) ? CFArrayGetCount(c_bridge_interfaces) : 0;
1062
1063 for (j = 0; j < nActive; j++) {
1064 SCBridgeInterfaceRef a_bridge;
1065 CFArrayRef a_bridge_interfaces;
1066 CFStringRef a_bridge_if;
1067 CFIndex a_count;
1068
1069 a_bridge = CFArrayGetValueAtIndex(active, j);
1070 a_bridge_if = SCNetworkInterfaceGetBSDName(a_bridge);
1071 a_bridge_interfaces = SCBridgeInterfaceGetMemberInterfaces(a_bridge);
1072 a_count = (a_bridge_interfaces != NULL) ? CFArrayGetCount(a_bridge_interfaces) : 0;
1073
1074 if (CFEqual(c_bridge_if, a_bridge_if)) {
1075 CFIndex c;
1076 Boolean if_list_change = FALSE;
1077
1078 found = TRUE;
1079
1080 if (!_SC_CFEqual(c_bridge_interfaces, a_bridge_interfaces)) {
1081 if_list_change = TRUE;
1082 }
1083 if (!if_list_change) {
1084 break; // if no change
1085 }
1086 if (s == -1) {
1087 s = inet_dgram_socket();
1088 if (s == -1) {
1089 _SCErrorSet(errno);
1090 ok = FALSE;
1091 goto done;
1092 }
1093 }
1094 if (!if_list_change) {
1095 break; // no if list changes
1096 }
1097
1098 /*
1099 * ensure that the first device of the bridge matches, if
1100 * not then we remove all current devices and add them
1101 * back in the preferred order.
1102 */
1103 if ((c_count > 0) &&
1104 (a_count > 0) &&
1105 !CFEqual(CFArrayGetValueAtIndex(c_bridge_interfaces, 0),
1106 CFArrayGetValueAtIndex(a_bridge_interfaces, 0))) {
1107 CFIndex a;
1108
1109 for (a = 0; a < a_count; a++) {
1110 SCNetworkInterfaceRef a_interface;
1111 CFStringRef a_interface_if;
1112
1113 a_interface = CFArrayGetValueAtIndex(a_bridge_interfaces, a);
1114 if (!CFArrayContainsValue(c_bridge_interfaces,
1115 CFRangeMake(0, c_count),
1116 a_interface)) {
1117 continue; // if already removed
1118 }
1119
1120 a_interface_if = SCNetworkInterfaceGetBSDName(a_interface);
1121 if (!__bridge_remove_interface(s, a_bridge_if, a_interface_if)) {
1122 ok = FALSE;
1123 }
1124 }
1125
1126 a_count = 0; // all active devices have been removed
1127 }
1128
1129 /*
1130 * add any devices which are not currently associated
1131 * with the bridge interface.
1132 */
1133 for (c = 0; c < c_count; c++) {
1134 SCNetworkInterfaceRef c_interface;
1135 SCNetworkInterfacePrivateRef c_interfacePrivate;
1136 CFStringRef c_interface_if;
1137
1138 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c);
1139 if ((a_count == 0) ||
1140 !CFArrayContainsValue(a_bridge_interfaces,
1141 CFRangeMake(0, a_count),
1142 c_interface)) {
1143 /*
1144 * check if this member interface can be added to a bridge.
1145 */
1146 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1147 if (!c_interfacePrivate->supportsBridge) {
1148 // if member not supported
1149 continue;
1150 }
1151
1152 /*
1153 * if this member interface is not currently part of the bridge.
1154 */
1155 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1156 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) {
1157 // if member could not be added
1158 ok = FALSE;
1159 }
1160 }
1161 }
1162
1163 break;
1164 }
1165 }
1166
1167 if (!found) {
1168 CFIndex c;
1169
1170 if (s == -1) {
1171 s = inet_dgram_socket();
1172 if (s == -1) {
1173 _SCErrorSet(errno);
1174 ok = FALSE;
1175 goto done;
1176 }
1177 }
1178
1179 /*
1180 * establish the new bridge interface.
1181 */
1182 if (!__createInterface(s, c_bridge_if)) {
1183 _SCErrorSet(errno);
1184 ok = FALSE;
1185 continue;
1186 }
1187
1188 /*
1189 * add the member interfaces
1190 */
1191 for (c = 0; c < c_count; c++) {
1192 SCNetworkInterfaceRef c_interface;
1193 SCNetworkInterfacePrivateRef c_interfacePrivate;
1194 CFStringRef c_interface_if;
1195
1196 c_interface = CFArrayGetValueAtIndex(c_bridge_interfaces, c);
1197 c_interfacePrivate = (SCNetworkInterfacePrivateRef)c_interface;
1198 if (!c_interfacePrivate->supportsBridge) {
1199 // if member not supported
1200 continue;
1201 }
1202
1203 c_interface_if = SCNetworkInterfaceGetBSDName(c_interface);
1204 if (!__bridge_add_interface(s, c_bridge_if, c_interface_if)) {
1205 // if member could not be added
1206 ok = FALSE;
1207 }
1208 }
1209 }
1210
1211 }
1212
1213 done :
1214
1215 if (active != NULL) CFRelease(active);
1216 if (config != NULL) CFRelease(config);
1217 if (s != -1) (void) close(s);
1218
1219 return ok;
1220 #else // IFT_BRIDGE
1221 return TRUE;
1222 #endif // IFT_BRIDGE
1223 }