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