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