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