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