1/*
2 * Copyright (c) 2004-2011, 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 * August 5, 2004			Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32#include <TargetConditionals.h>
33#include "scutil.h"
34#include "net.h"
35#include "prefs.h"
36
37
38#if	TARGET_OS_IPHONE
39#define	INLINE_PASSWORDS_USE_CFSTRING
40#endif	// TARGET_OS_IPHONE
41
42
43#pragma mark -
44#pragma mark Interface management
45
46
47static CFArrayRef
48_copy_interfaces()
49{
50	CFMutableArrayRef	interfaces;
51	CFArrayRef		real_interfaces;
52
53	real_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs);
54	if (real_interfaces == NULL) {
55		SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
56		return NULL;
57	}
58
59	interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
60
61	// include real interfaces
62	CFArrayAppendArray(interfaces,
63			   real_interfaces,
64			   CFRangeMake(0, CFArrayGetCount(real_interfaces)));
65	CFRelease(real_interfaces);
66
67	// include pseudo interfaces
68	CFArrayAppendValue(interfaces, kSCNetworkInterfaceLoopback);
69	CFArrayAppendValue(interfaces, kSCNetworkInterfaceIPv4);
70
71	// include interfaces that we have created
72	if (new_interfaces != NULL) {
73		CFArrayAppendArray(interfaces,
74				   new_interfaces,
75				   CFRangeMake(0, CFArrayGetCount(new_interfaces)));
76	}
77
78	return (CFArrayRef)interfaces;
79}
80
81
82__private_extern__
83SCNetworkInterfaceRef
84_find_interface(int argc, char **argv, int *nArgs)
85{
86	Boolean			allowIndex	= TRUE;
87	CFIndex			i;
88	CFArrayRef		myInterfaces	= interfaces;
89	CFIndex			n;
90	CFStringRef		select_name	= NULL;
91	SCNetworkInterfaceRef	selected	= NULL;
92
93	if (argc < 1) {
94		SCPrint(TRUE, stdout, CFSTR("no interface specified\n"));
95		return NULL;
96	}
97
98	if (nArgs != NULL) *nArgs = 1;
99
100	if (strcasecmp(argv[0], "$child") == 0) {
101		if (net_interface == NULL) {
102			SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
103			goto done;
104		}
105
106		selected = SCNetworkInterfaceGetInterface(net_interface);
107		if(selected == NULL) {
108			SCPrint(TRUE, stdout, CFSTR("no child interface\n"));
109		}
110
111		goto done;
112	} else if (strcasecmp(argv[0], "$service") == 0) {
113		if (net_service == NULL) {
114			SCPrint(TRUE, stdout, CFSTR("service not selected\n"));
115			goto done;
116		}
117
118		selected = SCNetworkServiceGetInterface(net_service);
119		if(selected == NULL) {
120			SCPrint(TRUE, stdout, CFSTR("no interface for service\n"));
121		}
122
123		goto done;
124	}
125
126#if	!TARGET_OS_IPHONE
127	else if (strcasecmp(argv[0], "$bond") == 0) {
128		CFStringRef	interfaceType;
129
130		if (net_interface == NULL) {
131			SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
132			goto done;
133		}
134
135		interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
136		if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
137			SCPrint(TRUE, stdout, CFSTR("interface not Bond\n"));
138			goto done;
139		}
140
141		if (argc < 2) {
142			SCPrint(TRUE, stdout, CFSTR("no member interface specified\n"));
143			return NULL;
144		}
145		argv++;
146		argc--;
147		if (nArgs != NULL) *nArgs += 1;
148
149		myInterfaces = SCBondInterfaceGetMemberInterfaces(net_interface);
150		if (myInterfaces == NULL) {
151			SCPrint(TRUE, stdout, CFSTR("no member interfaces\n"));
152			goto done;
153		}
154		allowIndex = FALSE;
155	}
156#endif	// !TARGET_OS_IPHONE
157
158	else if (strcasecmp(argv[0], "$bridge") == 0) {
159		CFStringRef	interfaceType;
160
161		if (net_interface == NULL) {
162			SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
163			goto done;
164		}
165
166		interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
167		if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
168			SCPrint(TRUE, stdout, CFSTR("interface not Bridge\n"));
169			goto done;
170		}
171
172		if (argc < 2) {
173			SCPrint(TRUE, stdout, CFSTR("no member interface specified\n"));
174			return NULL;
175		}
176		argv++;
177		argc--;
178		if (nArgs != NULL) *nArgs += 1;
179
180		myInterfaces = SCBridgeInterfaceGetMemberInterfaces(net_interface);
181		if (myInterfaces == NULL) {
182			SCPrint(TRUE, stdout, CFSTR("no member interfaces\n"));
183			goto done;
184		}
185		allowIndex = FALSE;
186	}
187
188	else if (strcasecmp(argv[0], "$vlan") == 0) {
189		CFStringRef	interfaceType;
190
191		if (net_interface == NULL) {
192			SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
193			goto done;
194		}
195
196		interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
197		if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
198			SCPrint(TRUE, stdout, CFSTR("interface not VLAN\n"));
199			goto done;
200		}
201
202		selected = SCVLANInterfaceGetPhysicalInterface(net_interface);
203		if(selected == NULL) {
204			SCPrint(TRUE, stdout, CFSTR("no physical interface\n"));
205		}
206
207		goto done;
208	}
209
210	if ((myInterfaces == NULL) && (interfaces == NULL)) {
211		interfaces = _copy_interfaces();
212		if (interfaces == NULL) {
213			return NULL;
214		}
215		myInterfaces = interfaces;
216		allowIndex = FALSE;
217	}
218
219	// try to select the interface by its display name
220
221	select_name = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
222
223	n = (myInterfaces != NULL) ? CFArrayGetCount(myInterfaces) : 0;
224	for (i = 0; i < n; i++) {
225		SCNetworkInterfaceRef	interface;
226		CFStringRef		interfaceName;
227
228		interface = CFArrayGetValueAtIndex(myInterfaces, i);
229		interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
230		if ((interfaceName != NULL) && CFEqual(select_name, interfaceName)) {
231			if (selected == NULL) {
232				selected = interface;
233			} else {
234				// if multiple interfaces match
235				selected = NULL;
236				SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
237				goto done;
238			}
239		}
240	}
241
242	if (selected != NULL) {
243		goto done;
244	}
245
246	// try to select the interface by its BSD name
247
248	for (i = 0; i < n; i++) {
249		SCNetworkInterfaceRef	interface;
250		CFStringRef		bsd_name	= NULL;
251
252		interface = CFArrayGetValueAtIndex(myInterfaces, i);
253		while ((interface != NULL) && (bsd_name == NULL)) {
254			bsd_name = SCNetworkInterfaceGetBSDName(interface);
255			if (bsd_name == NULL) {
256				interface = SCNetworkInterfaceGetInterface(interface);
257			}
258		}
259
260		if ((bsd_name != NULL) && CFEqual(select_name, bsd_name)) {
261			if (selected == NULL) {
262				selected = interface;
263			} else {
264				// if multiple interfaces match
265				selected = NULL;
266				SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
267				goto done;
268			}
269		}
270	}
271
272	if (selected != NULL) {
273		goto done;
274	}
275
276	// try to select the interface by its interface type
277
278	for (i = 0; i < n; i++) {
279		SCNetworkInterfaceRef	interface;
280		CFStringRef		interfaceType;
281
282		interface = CFArrayGetValueAtIndex(myInterfaces, i);
283		interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
284		if (CFEqual(select_name, interfaceType)) {
285			if (selected == NULL) {
286				selected = interface;
287			} else {
288				// if multiple interfaces match
289				selected = NULL;
290				SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
291				goto done;
292			}
293		}
294	}
295
296	if (selected != NULL) {
297		goto done;
298	}
299
300	if (allowIndex) {
301		char	*end;
302		char	*str	= argv[0];
303		long	val;
304
305		// try to select the interface by its index
306
307		errno = 0;
308		val = strtol(str, &end, 10);
309		if ((*str != '\0') &&
310		    ((*end == '\0') || (*end == '.')) &&
311		    (errno == 0)) {
312			if ((val > 0) && (val <= n)) {
313				selected = CFArrayGetValueAtIndex(myInterfaces, val - 1);
314
315				if (*end == '.') {
316					str = end + 1;
317					val = strtol(str, &end, 10);
318					if ((*str != '\0') && (*end == '\0') && (errno == 0)) {
319						while (val-- > 0) {
320							selected = SCNetworkInterfaceGetInterface(selected);
321							if (selected == NULL) {
322								break;
323							}
324						}
325					}
326				}
327			}
328		}
329	}
330
331	if (selected != NULL) {
332		goto done;
333	}
334
335	SCPrint(TRUE, stdout, CFSTR("no match\n"));
336
337    done :
338
339	if (select_name != NULL) CFRelease(select_name);
340	return selected;
341}
342
343
344/* -------------------- */
345
346
347__private_extern__
348void
349create_interface(int argc, char **argv)
350{
351	SCNetworkInterfaceRef	interface;
352	CFStringRef		interfaceName;
353	CFStringRef		interfaceType;
354	SCNetworkInterfaceRef	new_interface;
355
356	if (argc < 1) {
357		SCPrint(TRUE, stdout, CFSTR("what interface type?\n"));
358		return;
359	}
360
361	interfaceType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
362	argv++;
363	argc--;
364
365	if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
366		SCPrint(TRUE, stdout, CFSTR("bond creation not yet supported\n"));
367		goto done;
368	}
369	if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
370		SCPrint(TRUE, stdout, CFSTR("bridge creation not yet supported\n"));
371		goto done;
372	}
373	if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
374		SCPrint(TRUE, stdout, CFSTR("vlan creation not yet supported\n"));
375		goto done;
376	}
377
378	if (argc < 1) {
379		if (net_interface == NULL) {
380			SCPrint(TRUE, stdout, CFSTR("no network interface selected\n"));
381			goto done;
382		}
383
384		interface = net_interface;
385	} else {
386		interface = _find_interface(argc, argv, NULL);
387	}
388
389	if (interface == NULL) {
390		goto done;
391	}
392
393	new_interface = SCNetworkInterfaceCreateWithInterface(interface, interfaceType);
394	if (new_interface == NULL) {
395		SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
396		goto done;
397	}
398
399	if (new_interfaces == NULL) {
400		new_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
401	}
402	CFArrayAppendValue(new_interfaces, new_interface);
403
404	if (net_interface != NULL) CFRelease(net_interface);
405	net_interface = new_interface;
406
407	interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(net_interface);
408	if (interfaceName == NULL) {
409		interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
410	}
411	if (interfaceName == NULL) {
412		interfaceName = SCNetworkInterfaceGetInterfaceType(net_interface);
413	}
414	SCPrint(TRUE, stdout, CFSTR("interface \"%@\" created and selected\n"), interfaceName);
415
416    done :
417
418	CFRelease(interfaceType);
419	return;
420}
421
422
423/* -------------------- */
424
425
426__private_extern__
427void
428select_interface(int argc, char **argv)
429{
430	SCNetworkInterfaceRef	interface;
431
432	interface = _find_interface(argc, argv, NULL);
433	if (interface != NULL) {
434		CFStringRef	interfaceName;
435
436		if (net_interface != NULL) CFRelease(net_interface);
437		net_interface = CFRetain(interface);
438
439		interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
440		if (interfaceName == NULL) {
441			interfaceName = SCNetworkInterfaceGetBSDName(interface);
442		}
443		if (interfaceName == NULL) {
444			interfaceName = SCNetworkInterfaceGetInterfaceType(interface);
445		}
446
447		SCPrint(TRUE, stdout, CFSTR("interface \"%@\" selected\n"), interfaceName);
448	}
449
450	return;
451}
452
453
454/* -------------------- */
455
456
457__private_extern__
458void
459_show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean showChild)
460{
461	CFDictionaryRef configuration;
462	CFStringRef	if_bsd_name;
463	CFStringRef	if_localized_name;
464	CFStringRef	if_mac_address;
465	CFStringRef	if_type;
466	Boolean		isPhysicalEthernet;
467	CFArrayRef	supported;
468
469	if_localized_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
470	if (if_localized_name != NULL) {
471		SCPrint(TRUE, stdout, CFSTR("%@  name                 = %@\n"), prefix, if_localized_name);
472	}
473
474	if_bsd_name = SCNetworkInterfaceGetBSDName(interface);
475	if (if_bsd_name != NULL) {
476		SCPrint(TRUE, stdout, CFSTR("%@  interface name       = %@\n"), prefix, if_bsd_name);
477	}
478
479	if_type = SCNetworkInterfaceGetInterfaceType(interface);
480	SCPrint(TRUE, stdout, CFSTR("%@  type                 = %@\n"), prefix, if_type);
481
482	if_mac_address = SCNetworkInterfaceGetHardwareAddressString(interface);
483	if (if_mac_address != NULL) {
484		SCPrint(TRUE, stdout, CFSTR("%@  address              = %@\n"), prefix, if_mac_address);
485	}
486
487	configuration = SCNetworkInterfaceGetConfiguration(interface);
488	if ((configuration != NULL) &&
489	    CFDictionaryContainsKey(configuration, kSCResvInactive)) {
490		configuration = NULL;
491	}
492
493	if (if_bsd_name != NULL) {
494		CFArrayRef	available;
495		CFDictionaryRef	active;
496		CFDictionaryRef	cap_current;
497		int		mtu_cur;
498		int		mtu_min;
499		int		mtu_max;
500
501		cap_current = SCNetworkInterfaceCopyCapability(interface, NULL);
502		if (cap_current != NULL) {
503			CFIndex			i;
504			CFArrayRef		cap_names;
505			CFMutableArrayRef	cap_sorted;
506			const void		**keys;
507			CFIndex			n;
508
509			n = CFDictionaryGetCount(cap_current);
510			keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
511			CFDictionaryGetKeysAndValues(cap_current, keys, NULL);
512			cap_names = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
513			CFAllocatorDeallocate(NULL, keys);
514
515			cap_sorted = CFArrayCreateMutableCopy(NULL, 0, cap_names);
516			CFRelease(cap_names);
517
518			CFArraySortValues(cap_sorted, CFRangeMake(0, n), (CFComparatorFunction)CFStringCompare, NULL);
519
520			SCPrint(TRUE, stdout, CFSTR("%@  capabilities         = "), prefix);
521			for (i = 0; i < n; i++) {
522				CFStringRef	cap_name;
523				int		cap_val;
524				CFNumberRef	val	= NULL;
525
526				cap_name = CFArrayGetValueAtIndex(cap_sorted, i);
527				if (configuration != NULL) {
528					val = CFDictionaryGetValue(configuration, cap_name);
529				}
530				if (!isA_CFNumber(val)) {
531					val = CFDictionaryGetValue(cap_current, cap_name);
532				}
533
534				SCPrint(TRUE, stdout, CFSTR("%s%@%c"),
535					(i == 0) ? "" : ",",
536					cap_name,
537					(CFNumberGetValue(val, kCFNumberIntType, &cap_val) &&
538					 (cap_val != 0)) ? '+' : '-');
539			}
540			SCPrint(TRUE, stdout, CFSTR("\n"));
541
542			CFRelease(cap_sorted);
543			CFRelease(cap_current);
544		}
545
546		if (SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
547			char	isCurrent	= '*';
548
549			if (configuration != NULL) {
550				int		mtu_req;
551				CFNumberRef	num;
552
553				num = CFDictionaryGetValue(configuration, kSCPropNetEthernetMTU);
554				if (isA_CFNumber(num)) {
555					CFNumberGetValue(num, kCFNumberIntType, &mtu_req);
556					if (mtu_cur != mtu_req) {
557						mtu_cur = mtu_req;
558						isCurrent = ' ';
559					}
560				}
561			}
562
563			SCPrint(TRUE, stdout, CFSTR("%@  mtu                %c = %d (%d < n < %d)\n"),
564				prefix,
565				isCurrent,
566				mtu_cur,
567				mtu_min,
568				mtu_max);
569		}
570
571		if (SCNetworkInterfaceCopyMediaOptions(interface, NULL, &active, &available, TRUE)) {
572			char		isCurrent	= ' ';
573			CFArrayRef	options		= NULL;
574			CFArrayRef	options_req	= NULL;
575			CFStringRef	subtype		= NULL;
576			CFStringRef	subtype_req	= NULL;
577
578			if (configuration != NULL) {
579				subtype_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaSubType);
580				options_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaOptions);
581			}
582
583			if (subtype_req == NULL) {
584				subtype_req = CFSTR("autoselect");
585			}
586
587			if (active != NULL) {
588				subtype = CFDictionaryGetValue(active, kSCPropNetEthernetMediaSubType);
589				options = CFDictionaryGetValue(active, kSCPropNetEthernetMediaOptions);
590			}
591
592			if (subtype != NULL) {
593				if (((subtype_req != NULL) &&
594				     CFEqual(subtype, subtype_req)) &&
595				    ((options == options_req) ||
596				     ((options != NULL) &&
597				      (options_req != NULL) &&
598				      CFEqual(options, options_req)))
599				   ) {
600					isCurrent = '*';
601				} else if ((subtype_req == NULL) ||
602					   ((subtype_req != NULL) &&
603					    CFEqual(subtype_req, CFSTR("autoselect")))) {
604					// if requested subtype not specified or "autoselect"
605					isCurrent = '*';
606				}
607			}
608
609			if (subtype_req != NULL) {
610				SCPrint(TRUE, stdout, CFSTR("%@  media              %c = %@"),
611					prefix,
612					isCurrent,
613					subtype_req);
614
615				if ((options_req != NULL) &&
616				    (CFArrayGetCount(options_req) > 0)) {
617					CFStringRef	options_str;
618
619					options_str = CFStringCreateByCombiningStrings(NULL, options_req, CFSTR(","));
620					SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str);
621					CFRelease(options_str);
622				}
623
624				SCPrint(TRUE, stdout, CFSTR("\n"));
625			}
626
627			SCPrint(TRUE, stdout, CFSTR("\n"));
628
629			if (available != NULL) {
630				CFIndex		i;
631				CFIndex		n_subtypes;
632				CFArrayRef	subtypes;
633
634				subtypes   = SCNetworkInterfaceCopyMediaSubTypes(available);
635				n_subtypes = (subtypes != NULL) ? CFArrayGetCount(subtypes) : 0;
636				for (i = 0; i < n_subtypes; i++) {
637					CFIndex		j;
638					CFIndex		n_subtype_options;
639					CFStringRef	subtype;
640					CFArrayRef	subtype_options;
641
642					subtype = CFArrayGetValueAtIndex(subtypes, i);
643					subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
644					n_subtype_options = (subtype_options != NULL) ? CFArrayGetCount(subtype_options) : 0;
645					for (j = 0; j < n_subtype_options; j++) {
646						char		isCurrent	= ' ';
647						CFArrayRef	options;
648
649						options = CFArrayGetValueAtIndex(subtype_options, j);
650
651						if (((subtype_req != NULL) &&
652						     CFEqual(subtype, subtype_req)) &&
653						    ((options == options_req) ||
654						     ((options != NULL) &&
655						      (options_req != NULL) &&
656						      CFEqual(options, options_req)))
657						   ) {
658							isCurrent = '*';
659						}
660
661						SCPrint(TRUE, stdout, CFSTR("%@  %s    %c = %@"),
662							prefix,
663							((i == 0) && (j == 0)) ? "supported media" : "               ",
664							isCurrent,
665							subtype);
666
667						if ((options != NULL) &&
668						    (CFArrayGetCount(options) > 0)) {
669							CFStringRef	options_str;
670
671							options_str = CFStringCreateByCombiningStrings(NULL, options, CFSTR(","));
672							SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str);
673							CFRelease(options_str);
674						}
675
676						SCPrint(TRUE, stdout, CFSTR("\n"));
677					}
678					if (subtype_options != NULL) CFRelease(subtype_options);
679				}
680				if (subtypes != NULL) CFRelease(subtypes);
681			}
682		} else {
683			SCPrint(TRUE, stdout, CFSTR("\n"));
684		}
685	}
686
687	supported = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
688	SCPrint(TRUE, stdout, CFSTR("%@  supported interfaces = "), prefix);
689	if (supported != NULL) {
690		CFIndex i;
691		CFIndex n	= CFArrayGetCount(supported);
692
693		for (i = 0; i < n; i++) {
694			SCPrint(TRUE, stdout, CFSTR("%s%@"),
695				(i == 0) ? "" : ", ",
696				CFArrayGetValueAtIndex(supported, i));
697		}
698	}
699	SCPrint(TRUE, stdout, CFSTR("\n"));
700
701	supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
702	SCPrint(TRUE, stdout, CFSTR("%@  supported protocols  = "), prefix);
703	if (supported != NULL) {
704		CFIndex i;
705		CFIndex n	= CFArrayGetCount(supported);
706
707		for (i = 0; i < n; i++) {
708			SCPrint(TRUE, stdout, CFSTR("%s%@"),
709				(i == 0) ? "" : ", ",
710				CFArrayGetValueAtIndex(supported, i));
711		}
712	}
713	SCPrint(TRUE, stdout, CFSTR("\n"));
714
715	isPhysicalEthernet = _SCNetworkInterfaceIsPhysicalEthernet(interface);
716	SCPrint(TRUE, stdout, CFSTR("%@  is physical ethernet = %s \n"),
717		prefix, (isPhysicalEthernet == TRUE) ? "YES" : "NO");
718
719	if (configuration != NULL) {
720		CFMutableDictionaryRef	effective;
721
722		effective = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
723
724		// remove known (and already reported) interface configuration keys
725		if (CFDictionaryContainsKey(effective, kSCResvInactive)) {
726			CFDictionaryRemoveAllValues(effective);
727		}
728		CFDictionaryRemoveValue(effective, kSCPropNetEthernetMTU);
729		CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaSubType);
730		CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaOptions);
731
732		if (CFDictionaryGetCount(effective) > 0) {
733			SCPrint(TRUE, stdout, CFSTR("\n%@  per-interface configuration\n"), prefix);
734			_show_entity(effective, prefix);
735		}
736
737		CFRelease(effective);
738	}
739
740	if (CFEqual(if_type, kSCNetworkInterfaceTypePPP)) {
741		SCNetworkInterfaceRef	childInterface;
742
743		childInterface = SCNetworkInterfaceGetInterface(interface);
744		if (childInterface != NULL) {
745			CFStringRef	childInterfaceType;
746
747			childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
748			if (CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
749				CFDictionaryRef		ipsec_configuration;
750
751				ipsec_configuration = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
752				if (isA_CFDictionary(ipsec_configuration) &&
753				    (CFDictionaryGetCount(ipsec_configuration) > 0)) {
754					SCPrint(TRUE, stdout, CFSTR("\n%@  per-interface IPSec configuration\n"), prefix);
755					_show_entity(ipsec_configuration, prefix);
756				}
757			}
758		}
759	}
760
761	if (_sc_debug) {
762		SCPrint(TRUE, stdout, CFSTR("\n%@\n"), interface);
763	}
764
765	interface = SCNetworkInterfaceGetInterface(interface);
766	if (interface != NULL) {
767		CFStringRef	newPrefix;
768
769		newPrefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@  "), prefix);
770		SCPrint(TRUE, stdout, CFSTR("\n%@child interface\n"), newPrefix);
771		_show_interface(interface, newPrefix, showChild);
772		CFRelease(newPrefix);
773	}
774
775	return;
776}
777
778
779/* -------------------- */
780
781
782static Boolean
783validateMediaOptions(SCNetworkInterfaceRef interface, CFMutableDictionaryRef newConfiguration)
784{
785	Boolean		ok	= TRUE;
786	CFNumberRef	mtu;
787	CFArrayRef	options;
788	CFStringRef	subtype;
789
790	mtu = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMTU);
791	if (isA_CFNumber(mtu)) {
792		int	mtu_max;
793		int	mtu_min;
794		int	mtu_val;
795
796		if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) {
797			SCPrint(TRUE, stdout, CFSTR("cannot set MTU\n"));
798			return FALSE;
799		}
800
801		if (!CFNumberGetValue(mtu, kCFNumberIntType, &mtu_val) ||
802		    (mtu_val < mtu_min) ||
803		    (mtu_val > mtu_max)) {
804			SCPrint(TRUE, stdout, CFSTR("mtu out of range\n"));
805			return FALSE;
806		}
807	}
808
809	subtype = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaSubType);
810	options = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaOptions);
811
812	if (subtype != NULL) {
813		CFArrayRef	available	= NULL;
814		CFArrayRef	config_options	= options;
815		CFArrayRef	subtypes	= NULL;
816		CFArrayRef	subtype_options	= NULL;
817
818		ok = FALSE;
819
820		if (options == NULL) {
821			config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
822		}
823
824		if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) {
825			SCPrint(TRUE, stdout, CFSTR("media type / options not available\n"));
826			goto checked;
827		}
828
829		if (available == NULL) {
830			goto checked;
831		}
832
833		subtypes = SCNetworkInterfaceCopyMediaSubTypes(available);
834		if ((subtypes == NULL) ||
835		    !CFArrayContainsValue(subtypes,
836					 CFRangeMake(0, CFArrayGetCount(subtypes)),
837					 subtype)) {
838			SCPrint(TRUE, stdout, CFSTR("media type not valid\n"));
839			goto checked;
840		}
841
842		subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
843		if ((subtype_options == NULL) ||
844		    !CFArrayContainsValue(subtype_options,
845					  CFRangeMake(0, CFArrayGetCount(subtype_options)),
846					  config_options)) {
847			SCPrint(TRUE, stdout, CFSTR("media options not valid for \"%@\"\n"), subtype);
848			goto checked;
849		}
850
851		if (options == NULL) {
852			CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaOptions, config_options);
853		}
854
855		ok = TRUE;
856
857	    checked :
858
859		if (available       != NULL)	CFRelease(available);
860		if (subtypes        != NULL)	CFRelease(subtypes);
861		if (subtype_options != NULL)	CFRelease(subtype_options);
862		if (options         == NULL)	CFRelease(config_options);
863	} else {
864		if (options != NULL) {
865			SCPrint(TRUE, stdout, CFSTR("media type and options must both be specified\n"));
866			return FALSE;
867		}
868	}
869
870	return ok;
871}
872
873
874/* -------------------- */
875
876
877__private_extern__
878void
879show_interfaces(int argc, char **argv)
880{
881	CFIndex		i;
882	CFIndex		n;
883
884	if (interfaces != NULL) CFRelease(interfaces);
885	interfaces = _copy_interfaces();
886	if (interfaces == NULL) {
887		return;
888	}
889
890	n = CFArrayGetCount(interfaces);
891	for (i = 0; i < n; i++) {
892		CFIndex			childIndex	= 0;
893		SCNetworkInterfaceRef	interface;
894
895		interface = CFArrayGetValueAtIndex(interfaces, i);
896		do {
897			CFStringRef	interfaceName;
898			char		isSelected;
899
900			interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
901			if (interfaceName == NULL) {
902				interfaceName = SCNetworkInterfaceGetBSDName(interface);
903			}
904			if (interfaceName == NULL) {
905				interfaceName = SCNetworkInterfaceGetInterfaceType(interface);
906			}
907
908			isSelected = ' ';
909			if ((net_interface != NULL) && CFEqual(interface, net_interface)) {
910				isSelected = '>';
911			}
912
913			if (childIndex == 0) {
914				SCPrint(TRUE, stdout, CFSTR("%c%2d: %@\n"),
915					isSelected,
916					i + 1,
917					interfaceName);
918			} else {
919				SCPrint(TRUE, stdout, CFSTR("%c%2d.%d: %@\n"),
920					isSelected,
921					i + 1,
922					childIndex,
923					interfaceName);
924			}
925
926			if (_sc_debug) {
927				CFMutableStringRef	desc;
928				CFStringRef		str;
929
930				str = CFCopyDescription(interface);
931				desc = CFStringCreateMutableCopy(NULL, 0, str);
932				CFRelease(str);
933
934				CFStringFindAndReplace(desc,
935						       CFSTR(" {"),
936						       CFSTR("\n       {\n         "),
937						       CFRangeMake(0, CFStringGetLength(desc)),
938						       0);
939				CFStringFindAndReplace(desc,
940						       CFSTR(", "),
941						       CFSTR(",\n         "),
942						       CFRangeMake(0, CFStringGetLength(desc)),
943						       0);
944				CFStringFindAndReplace(desc,
945						       CFSTR("}"),
946						       CFSTR("\n       }"),
947						       CFRangeMake(0, CFStringGetLength(desc)),
948						       0);
949				SCPrint(TRUE, stdout, CFSTR("\n     %@\n\n"), desc);
950				CFRelease(desc);
951			}
952
953			interface = SCNetworkInterfaceGetInterface(interface);
954			childIndex++;
955		} while (interface != NULL);
956	}
957
958	return;
959}
960
961
962/* -------------------- */
963
964
965static int
966__doRank(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
967{
968	SCNetworkInterfaceRef		interface;
969	CFStringRef			interfaceName;
970	Boolean				ok	= FALSE;
971	SCNetworkServicePrimaryRank	rank	= kSCNetworkServicePrimaryRankDefault;
972	SCDynamicStoreRef		store;
973
974	if (argc < 1) {
975		SCPrint(TRUE, stdout,
976			CFSTR("%s not specified\n"),
977			description != NULL ? description : "rank");
978		return -1;
979	}
980
981	if (strlen(argv[0]) == 0) {
982		rank = kSCNetworkServicePrimaryRankDefault;
983	} else if ((strcasecmp(argv[0], "First") == 0)) {
984		rank = kSCNetworkServicePrimaryRankFirst;
985	} else if ((strcasecmp(argv[0], "Last") == 0)) {
986		rank = kSCNetworkServicePrimaryRankLast;
987	} else if ((strcasecmp(argv[0], "Never") == 0)) {
988		rank = kSCNetworkServicePrimaryRankNever;
989	} else {
990		SCPrint(TRUE, stdout, CFSTR("invalid rank\n"));
991		return -1;
992	}
993
994	interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
995	if (interfaceName == NULL) {
996		SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
997		return FALSE;
998	}
999
1000	store = SCDynamicStoreCreate(NULL, CFSTR("scutil --net"), NULL, NULL);
1001	interface = _SCNetworkInterfaceCopyActive(store, interfaceName);
1002	CFRelease(store);
1003	if (interface == NULL) {
1004		SCPrint(TRUE, stdout, CFSTR("No active interface\n"));
1005		return -1;
1006	}
1007
1008	ok = SCNetworkInterfaceSetPrimaryRank(interface, rank);
1009	CFRelease(interface);
1010	if (!ok) {
1011		SCPrint(TRUE, stdout, CFSTR("could not update per-interface rank\n"));
1012		return -1;
1013	}
1014
1015	return 1;
1016}
1017
1018
1019/* -------------------- */
1020
1021
1022static void
1023_replaceOne(const void *key, const void *value, void *context)
1024{
1025	CFMutableDictionaryRef	newConfiguration	= (CFMutableDictionaryRef)context;
1026
1027	CFDictionarySetValue(newConfiguration, key, value);
1028	return;
1029}
1030
1031
1032static void
1033updateInterfaceConfiguration(CFMutableDictionaryRef newConfiguration)
1034{
1035	CFDictionaryRef	configuration;
1036
1037	CFDictionaryRemoveAllValues(newConfiguration);
1038
1039	configuration = SCNetworkInterfaceGetConfiguration(net_interface);
1040	if (configuration != NULL) {
1041		CFDictionaryApplyFunction(configuration, _replaceOne, (void *)newConfiguration);
1042	}
1043
1044	return;
1045}
1046
1047
1048#pragma mark -
1049#pragma mark Bond options
1050
1051
1052static options bondOptions[] = {
1053	{ "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
1054	// xxx  { "+device"   , ... },
1055	// xxx  { "-device"   , ... },
1056
1057	{ "?"         , NULL , isHelp     , NULL                            , NULL,
1058		"\nBond configuration commands\n\n"
1059		" set interface [mtu n] [media type] [mediaopts opts]\n"
1060	}
1061};
1062#define	N_BOND_OPTIONS	(sizeof(bondOptions) / sizeof(bondOptions[0]))
1063
1064
1065static Boolean
1066set_interface_bond(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1067{
1068	CFStringRef	interfaceName;
1069	Boolean		ok;
1070
1071	interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1072	if (interfaceName == NULL) {
1073		SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1074		return FALSE;
1075	}
1076
1077	ok = _process_options(bondOptions, N_BOND_OPTIONS, argc, argv, newConfiguration);
1078	if (ok) {
1079		// validate configuration
1080		if (!validateMediaOptions(net_interface, newConfiguration)) {
1081			return FALSE;
1082		}
1083	}
1084
1085	return ok;
1086}
1087
1088
1089#pragma mark -
1090#pragma mark Bridge options
1091
1092
1093static options bridgeOptions[] = {
1094	{ "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
1095// xxx  { "+device"   , ... },
1096// xxx  { "-device"   , ... },
1097
1098	{ "?"         , NULL , isHelp     , NULL                            , NULL,
1099	    "\nBridge configuration commands\n\n"
1100	    " set interface [mtu n] [media type] [mediaopts opts]\n"
1101	}
1102};
1103#define	N_BRIDGE_OPTIONS	(sizeof(bridgeOptions) / sizeof(bridgeOptions[0]))
1104
1105
1106static Boolean
1107set_interface_bridge(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1108{
1109	CFStringRef	interfaceName;
1110	Boolean		ok;
1111
1112	interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1113	if (interfaceName == NULL) {
1114		SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1115		return FALSE;
1116	}
1117
1118	ok = _process_options(bridgeOptions, N_BRIDGE_OPTIONS, argc, argv, newConfiguration);
1119	if (ok) {
1120		// validate configuration
1121		if (!validateMediaOptions(net_interface, newConfiguration)) {
1122			return FALSE;
1123		}
1124	}
1125
1126	return ok;
1127}
1128
1129
1130#pragma mark -
1131#pragma mark AirPort options
1132
1133
1134static options airportOptions[] = {
1135	{ "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
1136	{ "media"     , NULL, isString     , &kSCPropNetEthernetMediaSubType, NULL, NULL },
1137	{ "mediaopt"  , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
1138
1139	{ "rank"      , NULL, isOther      , NULL                            , __doRank, NULL },
1140
1141	{ "?"         , NULL, isHelp       , NULL                            , NULL,
1142	    "\nAirPort configuration commands\n\n"
1143	    " set interface [mtu n] [media type] [mediaopts opts]\n"
1144	}
1145};
1146#define	N_AIRPORT_OPTIONS	(sizeof(airportOptions) / sizeof(airportOptions[0]))
1147
1148
1149static Boolean
1150set_interface_airport(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1151{
1152	CFStringRef	interfaceName;
1153	Boolean		ok;
1154
1155	interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1156	if (interfaceName == NULL) {
1157		SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1158		return FALSE;
1159	}
1160
1161	ok = _process_options(airportOptions, N_AIRPORT_OPTIONS, argc, argv, newConfiguration);
1162	if (ok) {
1163		// validate configuration
1164		if (!validateMediaOptions(net_interface, newConfiguration)) {
1165			return FALSE;
1166		}
1167	}
1168
1169	return ok;
1170}
1171
1172
1173#pragma mark -
1174#pragma mark Ethernet options
1175
1176
1177static int
1178__doCapability(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1179{
1180	Boolean	ok	= FALSE;
1181
1182	if (argc < 1) {
1183		SCPrint(TRUE, stdout,
1184			CFSTR("%s not specified\n"),
1185			description != NULL ? description : "enable/disable");
1186		return -1;
1187	}
1188
1189	if (strlen(argv[0]) == 0) {
1190		ok = SCNetworkInterfaceSetCapability(net_interface, key, NULL);
1191	} else if ((strcasecmp(argv[0], "disable") == 0) ||
1192		   (strcasecmp(argv[0], "no"     ) == 0) ||
1193		   (strcasecmp(argv[0], "off"    ) == 0) ||
1194		   (strcasecmp(argv[0], "0"      ) == 0)) {
1195		ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_0);
1196	} else if ((strcasecmp(argv[0], "enable") == 0) ||
1197		   (strcasecmp(argv[0], "yes"   ) == 0) ||
1198		   (strcasecmp(argv[0], "on"    ) == 0) ||
1199		   (strcasecmp(argv[0], "1"     ) == 0)) {
1200		ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_1);
1201	} else {
1202		SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
1203		return -1;
1204	}
1205
1206	if (ok) {
1207		updateInterfaceConfiguration(newConfiguration);
1208	} else {
1209		SCPrint(TRUE, stdout,
1210			CFSTR("%@ not updated: %s\n"),
1211			key,
1212			SCErrorString(SCError()));
1213		return -1;
1214	}
1215
1216	return 1;
1217}
1218
1219
1220static options ethernetOptions[] = {
1221	{ "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
1222	{ "media"     , NULL, isString     , &kSCPropNetEthernetMediaSubType, NULL, NULL },
1223	{ "mediaopt"  , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
1224
1225	{ "av"        , NULL, isOther      , &kSCPropNetEthernetCapabilityAV    , __doCapability, NULL },
1226	{ "lro"       , NULL, isOther      , &kSCPropNetEthernetCapabilityLRO   , __doCapability, NULL },
1227	{ "rxcsum"    , NULL, isOther      , &kSCPropNetEthernetCapabilityRXCSUM, __doCapability, NULL },
1228	{ "tso"       , NULL, isOther      , &kSCPropNetEthernetCapabilityTSO   , __doCapability, NULL },
1229	{ "txcsum"    , NULL, isOther      , &kSCPropNetEthernetCapabilityTXCSUM, __doCapability, NULL },
1230
1231	{ "rank"      , NULL, isOther      , NULL                            , __doRank, NULL },
1232
1233	{ "?"         , NULL, isHelp       , NULL                            , NULL,
1234	    "\nEthernet configuration commands\n\n"
1235	    " set interface [mtu n] [media type] [mediaopts opts]\n"
1236	}
1237};
1238#define	N_ETHERNET_OPTIONS	(sizeof(ethernetOptions) / sizeof(ethernetOptions[0]))
1239
1240
1241static Boolean
1242set_interface_ethernet(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1243{
1244	CFStringRef	interfaceName;
1245	Boolean		ok;
1246
1247	interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1248	if (interfaceName == NULL) {
1249		SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1250		return FALSE;
1251	}
1252
1253	ok = _process_options(ethernetOptions, N_ETHERNET_OPTIONS, argc, argv, newConfiguration);
1254	if (ok) {
1255		// validate configuration
1256		if (!validateMediaOptions(net_interface, newConfiguration)) {
1257			return FALSE;
1258		}
1259	}
1260
1261	return ok;
1262}
1263
1264
1265#pragma mark -
1266#pragma mark IPSec options
1267
1268
1269static int
1270__doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1271{
1272	CFStringRef	encryptionType;
1273
1274	if (argc < 1) {
1275		SCPrint(TRUE, stdout, CFSTR("IPSec shared secret not specified\n"));
1276		return -1;
1277	}
1278
1279	encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption);
1280	if (strlen(argv[0]) > 0) {
1281		if (encryptionType == NULL) {
1282#ifdef	INLINE_PASSWORDS_USE_CFSTRING
1283			CFStringRef		pw;
1284
1285			pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1286#else	// INLINE_PASSWORDS_USE_CFSTRING
1287			CFIndex			n;
1288			CFMutableDataRef	pw;
1289			CFStringRef		str;
1290
1291			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1292			n = CFStringGetLength(str);
1293			pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
1294			CFDataSetLength(pw, n * sizeof(UniChar));
1295			/* ALIGN: CF aligns to at least >8 bytes */
1296			CFStringGetCharacters(str,
1297					      CFRangeMake(0, n),
1298					      (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
1299			CFRelease(str);
1300#endif	// INLINE_PASSWORDS_USE_CFSTRING
1301
1302			CFDictionarySetValue(newConfiguration, key, pw);
1303			CFRelease(pw);
1304		} else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
1305			Boolean		ok;
1306			CFDataRef	pw;
1307			CFStringRef	str;
1308
1309			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1310			pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
1311			ok = SCNetworkInterfaceSetPassword(net_interface,
1312							   kSCNetworkInterfacePasswordTypeIPSecSharedSecret,
1313							   pw,
1314							   NULL);
1315			CFRelease(pw);
1316			CFRelease(str);
1317			if (ok) {
1318				updateInterfaceConfiguration(newConfiguration);
1319			} else {
1320				return -1;
1321			}
1322		} else {
1323			SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType);
1324			return -1;
1325		}
1326	} else {
1327		if (encryptionType == NULL) {
1328			CFDictionaryRemoveValue(newConfiguration, key);
1329		} else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
1330			Boolean		ok;
1331			ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecSharedSecret);
1332			if (ok) {
1333				updateInterfaceConfiguration(newConfiguration);
1334			} else {
1335				return -1;
1336			}
1337		} else {
1338			SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType);
1339			return -1;
1340		}
1341	}
1342
1343	return 1;
1344}
1345
1346
1347static int
1348__doIPSecSharedSecretType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1349{
1350	if (argc < 1) {
1351		SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type mode not specified\n"));
1352		return -1;
1353	}
1354
1355	if (strlen(argv[0]) > 0) {
1356		if (strcasecmp(argv[0], "keychain") == 0) {
1357			CFDictionarySetValue(newConfiguration, key, kSCValNetIPSecSharedSecretEncryptionKeychain);
1358		} else {
1359			SCPrint(TRUE, stdout, CFSTR("invalid shared secret type\n"));
1360			return -1;
1361		}
1362	} else {
1363		CFDictionaryRemoveValue(newConfiguration, key);
1364	}
1365
1366	// encryption type changed, reset shared secret
1367	CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPSecSharedSecret);
1368
1369	return 1;
1370}
1371
1372
1373static int
1374__doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1375{
1376	CFStringRef	encryptionType;
1377
1378	if (argc < 1) {
1379		SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password not specified\n"));
1380		return -1;
1381	}
1382
1383	encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption);
1384	if (strlen(argv[0]) > 0) {
1385		if (encryptionType == NULL) {
1386#ifdef	INLINE_PASSWORDS_USE_CFSTRING
1387			CFStringRef		pw;
1388
1389			pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1390#else	// INLINE_PASSWORDS_USE_CFSTRING
1391			CFIndex			n;
1392			CFMutableDataRef	pw;
1393			CFStringRef		str;
1394
1395			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1396			n = CFStringGetLength(str);
1397			pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
1398			CFDataSetLength(pw, n * sizeof(UniChar));
1399			/* ALIGN: CF aligns to at least >8 byte boundries */
1400			CFStringGetCharacters(str,
1401					      CFRangeMake(0, n),
1402					      (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
1403			CFRelease(str);
1404#endif	// INLINE_PASSWORDS_USE_CFSTRING
1405
1406			CFDictionarySetValue(newConfiguration, key, pw);
1407			CFRelease(pw);
1408		} else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
1409			Boolean		ok;
1410			CFDataRef	pw;
1411			CFStringRef	str;
1412
1413			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1414			pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
1415			ok = SCNetworkInterfaceSetPassword(net_interface,
1416							   kSCNetworkInterfacePasswordTypeIPSecXAuth,
1417							   pw,
1418							   NULL);
1419			CFRelease(pw);
1420			CFRelease(str);
1421			if (ok) {
1422				updateInterfaceConfiguration(newConfiguration);
1423			} else {
1424				return -1;
1425			}
1426		} else {
1427			SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType);
1428			return -1;
1429		}
1430	} else {
1431		if (encryptionType == NULL) {
1432			CFDictionaryRemoveValue(newConfiguration, key);
1433		} else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
1434			Boolean		ok;
1435
1436			ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecXAuth);
1437			if (ok) {
1438				updateInterfaceConfiguration(newConfiguration);
1439			} else {
1440				return -1;
1441			}
1442		} else {
1443			SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType);
1444			return -1;
1445		}
1446	}
1447
1448	return 1;
1449}
1450
1451
1452static int
1453__doIPSecXAuthPasswordType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1454{
1455	if (argc < 1) {
1456		SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password type mode not specified\n"));
1457		return -1;
1458	}
1459
1460	if (strlen(argv[0]) > 0) {
1461		if (strcasecmp(argv[0], "keychain") == 0) {
1462			CFDictionarySetValue(newConfiguration, key, kSCValNetIPSecXAuthPasswordEncryptionKeychain);
1463		} else {
1464			SCPrint(TRUE, stdout, CFSTR("invalid XAuth password type\n"));
1465			return -1;
1466		}
1467	} else {
1468		CFDictionaryRemoveValue(newConfiguration, key);
1469	}
1470
1471	// encryption type changed, reset XAuthPassword
1472	CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPSecXAuthPassword);
1473
1474	return 1;
1475}
1476
1477
1478static CF_RETURNS_RETAINED CFStringRef
1479__cleanupDomainName(CFStringRef domain)
1480{
1481	CFMutableStringRef	newDomain;
1482
1483	newDomain = CFStringCreateMutableCopy(NULL, 0, domain);
1484	CFStringTrimWhitespace(newDomain);
1485	CFStringTrim(newDomain, CFSTR("."));
1486	if (CFStringGetLength(newDomain) == 0) {
1487		CFRelease(newDomain);
1488		newDomain = NULL;
1489	}
1490
1491	return newDomain;
1492}
1493
1494
1495static int
1496__doOnDemandDomains(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1497{
1498	CFMutableArrayRef	domains;
1499
1500	if (argc < 1) {
1501		SCPrint(TRUE, stdout, CFSTR("OnDemand domain name(s) not specified\n"));
1502		return -1;
1503	}
1504
1505	domains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1506
1507	if (strlen(argv[0]) > 0) {
1508		CFArrayRef	array;
1509		CFStringRef	str;
1510
1511		str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1512		array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(","));
1513		CFRelease(str);
1514
1515		if (array != NULL) {
1516			CFIndex	i;
1517			CFIndex	n	= CFArrayGetCount(array);
1518
1519			for (i = 0; i < n; i++) {
1520				CFStringRef	domain;
1521
1522				domain = __cleanupDomainName(CFArrayGetValueAtIndex(array, i));
1523				if (domain != NULL) {
1524					CFArrayAppendValue(domains, domain);
1525					CFRelease(domain);
1526				} else {
1527					CFRelease(array);
1528					CFRelease(domains);
1529					SCPrint(TRUE, stdout, CFSTR("invalid OnDemand domain name\n"));
1530					return -1;
1531				}
1532			}
1533			CFRelease(array);
1534		}
1535	}
1536
1537	if (CFArrayGetCount(domains) > 0) {
1538		CFDictionarySetValue(newConfiguration, key, domains);
1539	} else {
1540		CFDictionaryRemoveValue(newConfiguration, key);
1541	}
1542
1543	CFRelease(domains);
1544	return 1;
1545}
1546
1547
1548static options ipsecOnDemandOptions[] = {
1549	{ "OnDemandMatchDomainsAlways" , "domain", isOther  , &kSCPropNetIPSecOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1550	{   "always"                   , "domain", isOther  , &kSCPropNetIPSecOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1551	{ "OnDemandMatchDomainsOnRetry", "domain", isOther  , &kSCPropNetIPSecOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1552	{   "retry"                    , "domain", isOther  , &kSCPropNetIPSecOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1553	{ "OnDemandMatchDomainsNever"  , "domain", isOther  , &kSCPropNetIPSecOnDemandMatchDomainsNever  , __doOnDemandDomains, NULL },
1554	{   "never"                    , "domain", isOther  , &kSCPropNetIPSecOnDemandMatchDomainsNever  , __doOnDemandDomains, NULL },
1555
1556	{ "?"                          , NULL    , isHelp , NULL                                       , NULL               ,
1557	    "\nOnDemandMatch configuration commands\n\n"
1558	    " set interface OnDemandMatch always domain-name[,domain-name]\n"
1559	    " set interface OnDemandMatch retry  domain-name[,domain-name]\n"
1560	    " set interface OnDemandMatch never  domain-name[,domain-name]\n"
1561	}
1562};
1563#define	N_IPSEC_ONDEMAND_OPTIONS	(sizeof(ipsecOnDemandOptions) / sizeof(ipsecOnDemandOptions[0]))
1564
1565
1566static int
1567__doIPSecOnDemandMatch(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1568{
1569	Boolean	ok;
1570
1571	if (argc < 1) {
1572		SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1573		return -1;
1574	}
1575
1576	ok = _process_options(ipsecOnDemandOptions, N_IPSEC_ONDEMAND_OPTIONS, argc, argv, newConfiguration);
1577	if (!ok) {
1578		goto done;
1579	}
1580
1581    done :
1582
1583	return argc;
1584}
1585
1586
1587static selections ipsecAuthenticationMethodSelections[] = {
1588	{ CFSTR("SharedSecret"), &kSCValNetIPSecAuthenticationMethodSharedSecret, 0 },
1589	{ CFSTR("Certificate") , &kSCValNetIPSecAuthenticationMethodCertificate , 0 },
1590	{ CFSTR("Hybrid")      , &kSCValNetIPSecAuthenticationMethodHybrid      , 0 },
1591	{ NULL                 , NULL                                           , 0 }
1592};
1593
1594
1595static selections ipsecLocalIdentifierTypeSelections[] = {
1596	{ CFSTR("KeyID")       , &kSCValNetIPSecLocalIdentifierTypeKeyID        , 0 },
1597	{ NULL                 , NULL                                           , 0 }
1598};
1599
1600
1601static options ipsecOptions[] = {
1602	{ "AuthenticationMethod"   , NULL, isChooseOne  , &kSCPropNetIPSecAuthenticationMethod   , NULL                      , (void *)ipsecAuthenticationMethodSelections },
1603	{ "LocalIdentifier"        , NULL, isString     , &kSCPropNetIPSecLocalIdentifier        , NULL                      , NULL                                        },
1604	{   "group"                , NULL, isString     , &kSCPropNetIPSecLocalIdentifier        , NULL                      , NULL                                        },
1605	{ "LocalIdentifierType"    , NULL, isChooseOne  , &kSCPropNetIPSecLocalIdentifierType    , NULL                      , (void *)ipsecLocalIdentifierTypeSelections  },
1606	{ "RemoteAddress"          , NULL, isString     , &kSCPropNetIPSecRemoteAddress          , NULL                      , NULL                                        },
1607	{ "SharedSecret"           , NULL, isOther      , &kSCPropNetIPSecSharedSecret           , __doIPSecSharedSecret     , NULL                                        },
1608	{ "SharedSecretEncryption" , NULL, isOther      , &kSCPropNetIPSecSharedSecretEncryption , __doIPSecSharedSecretType , NULL                                        },
1609
1610	// --- XAuth: ---
1611	{ "XAuthEnabled"           , NULL, isBoolean    , &kSCPropNetIPSecXAuthEnabled           , NULL                      , NULL                                        },
1612	{ "XAuthName"              , NULL, isString     , &kSCPropNetIPSecXAuthName              , NULL                      , NULL                                        },
1613	{ "XAuthPassword"          , NULL, isOther      , &kSCPropNetIPSecXAuthPassword          , __doIPSecXAuthPassword    , NULL                                        },
1614	{ "XAuthPasswordEncryption", NULL, isOther      , &kSCPropNetIPSecXAuthPasswordEncryption, __doIPSecXAuthPasswordType, NULL                                        },
1615
1616	// --- OnDemand: ---
1617	{ "OnDemandEnabled"        , NULL, isBoolean    , &kSCPropNetIPSecOnDemandEnabled        , NULL                      , NULL },
1618	{ "OnDemandMatch"          , NULL, isOther      , NULL                                   , __doIPSecOnDemandMatch    , NULL },
1619
1620	{ "?"         , NULL , isHelp     , NULL                            , NULL,
1621		"\nIPSec configuration commands\n\n"
1622		" set interface [AuthenticationMethod {SharedSecret|Certificate|Hybrid}]\n"
1623		" set interface [LocalIdentifier group]\n"
1624		" set interface [LocalIdentifierType {KeyID}]\n"
1625		" set interface [RemoteAddress name-or-address]\n"
1626		" set interface [SharedSecret secret]\n"
1627		" set interface [SharedSecretEncryption {Keychain}]\n"
1628		" set interface [XAuthEnabled {enable|disable}]\n"
1629		" set interface [XAuthPassword password]\n"
1630		" set interface [XAuthPasswordEncryption {Keychain}]\n"
1631		" set interface [OnDemandEnabled {enable|disable}]\n"
1632		" set interface [OnDemandMatch <match-options>]\n"
1633	}
1634};
1635#define	N_IPSEC_OPTIONS	(sizeof(ipsecOptions) / sizeof(ipsecOptions[0]))
1636
1637
1638static Boolean
1639set_interface_ipsec(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1640{
1641	Boolean		ok;
1642
1643	ok = _process_options(ipsecOptions, N_IPSEC_OPTIONS, argc, argv, newConfiguration);
1644	return ok;
1645}
1646
1647
1648#pragma mark -
1649#pragma mark FireWire options
1650
1651
1652static options firewireOptions[] = {
1653	{ "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
1654	{ "media"     , NULL, isString     , &kSCPropNetEthernetMediaSubType, NULL, NULL },
1655	{ "mediaopt"  , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
1656
1657	{ "?"         , NULL , isHelp     , NULL                            , NULL,
1658	    "\nFireWire configuration commands\n\n"
1659	    " set interface [mtu n] [media type] [mediaopts opts]\n"
1660	}
1661};
1662#define	N_FIREWIRE_OPTIONS	(sizeof(firewireOptions) / sizeof(firewireOptions[0]))
1663
1664
1665static Boolean
1666set_interface_firewire(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1667{
1668	CFStringRef	interfaceName;
1669	Boolean		ok;
1670
1671	interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1672	if (interfaceName == NULL) {
1673		SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1674		return FALSE;
1675	}
1676
1677	ok = _process_options(firewireOptions, N_FIREWIRE_OPTIONS, argc, argv, newConfiguration);
1678	if (ok) {
1679		// validate configuration
1680		if (!validateMediaOptions(net_interface, newConfiguration)) {
1681			return FALSE;
1682		}
1683	}
1684
1685	return ok;
1686}
1687
1688
1689#pragma mark -
1690#pragma mark Modem options
1691
1692
1693static selections modemDialSelections[] = {
1694	{ CFSTR("ignore"), &kSCValNetModemDialModeIgnoreDialTone , 0 },
1695	{ CFSTR("manual"), &kSCValNetModemDialModeManual         , 0 },
1696	{ CFSTR("wait")  , &kSCValNetModemDialModeWaitForDialTone, 0 },
1697	{ NULL           , NULL                                  , 0 }
1698};
1699
1700static options modemOptions[] = {
1701	{ "ConnectionScript"             , "script", isString   , &kSCPropNetModemConnectionScript           , NULL, NULL                        },
1702	{ "DialMode"                     , "mode"  , isChooseOne, &kSCPropNetModemDialMode                   , NULL, (void *)modemDialSelections },
1703	{ "CallWaiting"                  , NULL    , isBoolean  , &kSCPropNetModemHoldEnabled                , NULL, NULL                        },
1704	{ "CallWaitingAlert"             , NULL    , isBoolean  , &kSCPropNetModemHoldCallWaitingAudibleAlert, NULL, NULL                        },
1705	{ "CallWaitingDisconnectOnAnswer", NULL    , isBoolean  , &kSCPropNetModemHoldDisconnectOnAnswer     , NULL, NULL                        },
1706	{ "DataCompression"              , NULL    , isBoolean  , &kSCPropNetModemDataCompression            , NULL, NULL                        },
1707	{ "ErrorCorrection"              , NULL    , isBoolean  , &kSCPropNetModemErrorCorrection            , NULL, NULL                        },
1708	{ "HoldReminder"                 , NULL    , isBoolean  , &kSCPropNetModemHoldReminder               , NULL, NULL                        },
1709	{ "HoldReminderTime"             , "time"  , isNumber   , &kSCPropNetModemHoldReminderTime           , NULL, NULL                        },
1710	{ "PulseDial"                    , NULL    , isBoolean  , &kSCPropNetModemPulseDial                  , NULL, NULL                        },
1711	{ "Speaker"                      , NULL    , isBoolean  , &kSCPropNetModemSpeaker                    , NULL, NULL                        },
1712
1713	{ "?"                            , NULL    , isHelp     , NULL                                       , NULL,
1714	    "\nModem configuration commands\n\n"
1715	    " set interface [ConnectionScript connection-script]\n"
1716	    " set interface [CallWaiting {enable|disable}]\n"
1717	    " set interface [CallWaitingAlert {enable|disable}]\n"
1718	    " set interface [CallWaitingDisconnectOnAnswer {enable|disable}]\n"
1719	    " set interface [DialMode {ignore|wait}]\n"
1720	    " set interface [DataCompression {enable|disable}]\n"
1721	    " set interface [ErrorCorrection {enable|disable}]\n"
1722	    " set interface [HoldReminder {enable|disable}]\n"
1723	    " set interface [HoldReminderTime n]\n"
1724	    " set interface [PulseDial {enable|disable}]\n"
1725	    " set interface [Speaker {enable|disable}]\n"
1726	}
1727};
1728#define	N_MODEM_OPTIONS	(sizeof(modemOptions) / sizeof(modemOptions[0]))
1729
1730
1731static Boolean
1732set_interface_modem(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1733{
1734	Boolean	ok;
1735
1736	ok = _process_options(modemOptions, N_MODEM_OPTIONS, argc, argv, newConfiguration);
1737	return ok;
1738}
1739
1740
1741#pragma mark -
1742#pragma mark PPP options
1743
1744
1745static int
1746__doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1747{
1748	CFStringRef	encryptionType;
1749
1750	if (argc < 1) {
1751		SCPrint(TRUE, stdout, CFSTR("PPP password not specified\n"));
1752		return -1;
1753	}
1754
1755	encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption);
1756	if (strlen(argv[0]) > 0) {
1757		if (encryptionType == NULL) {
1758#ifdef	INLINE_PASSWORDS_USE_CFSTRING
1759			CFStringRef		pw;
1760
1761			pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1762#else	// INLINE_PASSWORDS_USE_CFSTRING
1763			CFIndex			n;
1764			CFMutableDataRef	pw;
1765			CFStringRef		str;
1766
1767			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1768			n = CFStringGetLength(str);
1769			pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
1770			CFDataSetLength(pw, n * sizeof(UniChar));
1771			/* ALIGN: CF aligns to at least >8 byte boundries */
1772			CFStringGetCharacters(str,
1773					      CFRangeMake(0, n),
1774					      (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
1775			CFRelease(str);
1776#endif	// INLINE_PASSWORDS_USE_CFSTRING
1777
1778			CFDictionarySetValue(newConfiguration, key, pw);
1779			CFRelease(pw);
1780		} else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
1781			Boolean		ok;
1782			CFDataRef	pw;
1783			CFStringRef	str;
1784
1785			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1786			pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
1787			ok = SCNetworkInterfaceSetPassword(net_interface,
1788							   kSCNetworkInterfacePasswordTypePPP,
1789							   pw,
1790							   NULL);
1791			CFRelease(pw);
1792			CFRelease(str);
1793			if (ok) {
1794				updateInterfaceConfiguration(newConfiguration);
1795			} else {
1796				return -1;
1797			}
1798		} else {
1799			SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
1800			return -1;
1801		}
1802	} else {
1803		if (encryptionType == NULL) {
1804			CFDictionaryRemoveValue(newConfiguration, key);
1805		} else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
1806			Boolean		ok;
1807
1808			ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypePPP);
1809			if (ok) {
1810				updateInterfaceConfiguration(newConfiguration);
1811			} else {
1812				return -1;
1813			}
1814		} else {
1815			SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
1816			return -1;
1817		}
1818	}
1819
1820	return 1;
1821}
1822
1823
1824static int
1825__doPPPAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1826{
1827	if (argc < 1) {
1828		SCPrint(TRUE, stdout, CFSTR("PPP password type mode not specified\n"));
1829		return -1;
1830	}
1831
1832	if (strlen(argv[0]) > 0) {
1833		if (strcasecmp(argv[0], "keychain") == 0) {
1834			CFDictionarySetValue(newConfiguration, key, kSCValNetPPPAuthPasswordEncryptionKeychain);
1835		} else {
1836			SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
1837			return -1;
1838		}
1839	} else {
1840		CFDictionaryRemoveValue(newConfiguration, key);
1841	}
1842
1843	// encryption type changed, reset password
1844	CFDictionaryRemoveValue(newConfiguration, kSCPropNetPPPAuthPassword);
1845
1846	return 1;
1847}
1848
1849
1850static options l2tp_ipsecOptions[] = {
1851	{ "SharedSecret"          , NULL, isOther      , &kSCPropNetIPSecSharedSecret          , __doIPSecSharedSecret    , NULL                                        },
1852	{ "SharedSecretEncryption", NULL, isOther      , &kSCPropNetIPSecSharedSecretEncryption, __doIPSecSharedSecretType, NULL                                        },
1853
1854	{ "?"         , NULL , isHelp     , NULL                            , NULL,
1855		"\nIPSec configuration commands\n\n"
1856		" set interface ipsec [SharedSecret secret]\n"
1857		" set interface ipsec [SharedSecretEncryption {Keychain}]\n"
1858	}
1859};
1860#define	N_L2TP_IPSEC_OPTIONS	(sizeof(l2tp_ipsecOptions) / sizeof(l2tp_ipsecOptions[0]))
1861
1862
1863static int
1864__doPPPIPSec(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newPPPConfiguration)
1865{
1866	SCNetworkInterfaceRef	childInterface;
1867	CFStringRef		childInterfaceType;
1868	CFDictionaryRef		configuration;
1869	CFMutableDictionaryRef	newConfiguration;
1870	Boolean			ok;
1871
1872	if (argc < 1) {
1873		SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1874		return -1;
1875	}
1876
1877	childInterface = SCNetworkInterfaceGetInterface(net_interface);
1878	if (childInterface == NULL) {
1879		SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
1880		return -1;
1881	}
1882
1883	childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
1884	if (!CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
1885		SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
1886		return -1;
1887	}
1888
1889	configuration = SCNetworkInterfaceGetExtendedConfiguration(net_interface, kSCEntNetIPSec);
1890	if (configuration == NULL) {
1891		newConfiguration = CFDictionaryCreateMutable(NULL,
1892							     0,
1893							     &kCFTypeDictionaryKeyCallBacks,
1894							     &kCFTypeDictionaryValueCallBacks);
1895	} else {
1896		newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1897		CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1898	}
1899
1900	ok = _process_options(l2tp_ipsecOptions, N_L2TP_IPSEC_OPTIONS, argc, argv, newConfiguration);
1901	if (!ok) {
1902		goto done;
1903	}
1904
1905	if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
1906	    ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
1907		if (!SCNetworkInterfaceSetExtendedConfiguration(net_interface, kSCEntNetIPSec, newConfiguration)) {
1908			if (SCError() == kSCStatusNoKey) {
1909				SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n"));
1910			} else {
1911				SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1912			}
1913			goto done;
1914		}
1915
1916		_prefs_changed = TRUE;
1917	}
1918
1919    done :
1920
1921	if (newConfiguration != NULL) CFRelease(newConfiguration);
1922	return argc;
1923}
1924
1925
1926#ifdef	NOTYET
1927static options pppOnDemandOptions[] = {
1928	{ "OnDemandMatchDomainsAlways" , "domain", isOther  , &kSCPropNetPPPOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1929	{   "always"                   , "domain", isOther  , &kSCPropNetPPPOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1930	{ "OnDemandMatchDomainsOnRetry", "domain", isOther  , &kSCPropNetPPPOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1931	{   "retry"                    , "domain", isOther  , &kSCPropNetPPPOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1932	{ "OnDemandMatchDomainsNever"  , "domain", isOther  , &kSCPropNetPPPOnDemandMatchDomainsNever  , __doOnDemandDomains, NULL },
1933	{   "never"                    , "domain", isOther  , &kSCPropNetPPPOnDemandMatchDomainsNever  , __doOnDemandDomains, NULL },
1934
1935	{ "?"                          , NULL    , isHelp , NULL                                     , NULL               ,
1936	    "\nOnDemandMatch configuration commands\n\n"
1937	    " set interface OnDemand always domain-name[,domain-name]\n"
1938	    " set interface OnDemand retry  domain-name[,domain-name]\n"
1939	    " set interface OnDemand never  domain-name[,domain-name]\n"
1940	}
1941};
1942#define	N_PPP_ONDEMAND_OPTIONS	(sizeof(pppOnDemandOptions) / sizeof(pppOnDemandOptions[0]))
1943
1944
1945static int
1946__doPPPOnDemandMatch(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1947{
1948	Boolean	ok;
1949
1950	if (argc < 1) {
1951		SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1952		return -1;
1953	}
1954
1955	ok = _process_options(pppOnDemandOptions, N_PPP_ONDEMAND_OPTIONS, argc, argv, newConfiguration);
1956	if (!ok) {
1957		goto done;
1958	}
1959
1960    done :
1961
1962	return argc;
1963}
1964#endif	// NOTYET
1965
1966
1967static selections authPromptSelections[] = {
1968	{ CFSTR("before"), &kSCValNetPPPAuthPromptBefore, 0 },
1969	{ CFSTR("after") , &kSCValNetPPPAuthPromptAfter , 0 },
1970	{ NULL    , NULL                                , 0 }
1971};
1972
1973
1974static selections authProtocolSelections[] = {
1975	{ CFSTR("CHAP")   , &kSCValNetPPPAuthProtocolCHAP   , 0 },
1976	{ CFSTR("EAP")    , &kSCValNetPPPAuthProtocolEAP    , 0 },
1977	{ CFSTR("MSCHAP1"), &kSCValNetPPPAuthProtocolMSCHAP1, 0 },
1978	{ CFSTR("MSCHAP2"), &kSCValNetPPPAuthProtocolMSCHAP2, 0 },
1979	{ CFSTR("PAP")    , &kSCValNetPPPAuthProtocolPAP    , 0 },
1980	{ NULL            , NULL                            , 0 }
1981};
1982
1983
1984static options pppOptions[] = {
1985	{ "ACSP"                      , NULL          , isBoolean        , &kSCPropNetPPPACSPEnabled               , NULL                , NULL                           },
1986	{ "ConnectTime"               , "?time"       , isNumber         , &kSCPropNetPPPConnectTime               , NULL                , NULL                           },
1987	{ "DialOnDemand"              , NULL          , isBoolean        , &kSCPropNetPPPDialOnDemand              , NULL                , NULL                           },
1988	{ "DisconnectOnFastUserSwitch", NULL          , isBoolean        , &kSCPropNetPPPDisconnectOnFastUserSwitch, NULL                , NULL                           },
1989	{ "DisconnectOnIdle"          , NULL          , isBoolean        , &kSCPropNetPPPDisconnectOnIdle          , NULL                , NULL                           },
1990	{ "DisconnectOnIdleTimer"     , "timeout"     , isNumber         , &kSCPropNetPPPDisconnectOnIdleTimer     , NULL                , NULL                           },
1991	{ "DisconnectOnLogout"        , NULL          , isBoolean        , &kSCPropNetPPPDisconnectOnLogout        , NULL                , NULL                           },
1992	{ "DisconnectOnSleep"         , NULL          , isBoolean        , &kSCPropNetPPPDisconnectOnSleep         , NULL                , NULL                           },
1993	{ "DisconnectTime"            , "?time"       , isNumber         , &kSCPropNetPPPDisconnectTime            , NULL                , NULL                           },
1994	{ "IdleReminder"              , NULL          , isBoolean        , &kSCPropNetPPPIdleReminder              , NULL                , NULL                           },
1995	{ "IdleReminderTimer"         , "time"        , isNumber         , &kSCPropNetPPPIdleReminderTimer         , NULL                , NULL                           },
1996	{ "Logfile"                   , "path"        , isString         , &kSCPropNetPPPLogfile                   , NULL                , NULL                           },
1997	{ "Plugins"                   , "plugin"      , isStringArray    , &kSCPropNetPPPPlugins                   , NULL                , NULL                           },
1998	{ "RetryConnectTime"          , "time"        , isNumber         , &kSCPropNetPPPRetryConnectTime          , NULL                , NULL                           },
1999	{ "SessionTimer"              , "time"        , isNumber         , &kSCPropNetPPPSessionTimer              , NULL                , NULL                           },
2000	{ "UseSessionTimer"           , NULL          , isBoolean        , &kSCPropNetPPPUseSessionTimer           , NULL                , NULL                           },
2001	{ "VerboseLogging"            , NULL          , isBoolean        , &kSCPropNetPPPVerboseLogging            , NULL                , NULL                           },
2002
2003	// --- Auth: ---
2004	{ "AuthEAPPlugins"            , "plugin"      , isStringArray    , &kSCPropNetPPPAuthEAPPlugins            , NULL                , NULL                           },
2005	{ "AuthName"                  , "account"     , isString         , &kSCPropNetPPPAuthName                  , NULL                , NULL                           },
2006	{   "Account"                 , "account"     , isString         , &kSCPropNetPPPAuthName                  , NULL                , NULL                           },
2007	{ "AuthPassword"              , "password"    , isOther          , &kSCPropNetPPPAuthPassword              , __doPPPAuthPW       , NULL                           },
2008	{   "Password"                , "password"    , isOther          , &kSCPropNetPPPAuthPassword              , __doPPPAuthPW       , NULL                           },
2009	{ "AuthPasswordEncryption"    , "type"        , isOther          , &kSCPropNetPPPAuthPasswordEncryption    , __doPPPAuthPWType   , NULL                           },
2010	{ "AuthPrompt"                , "before/after", isChooseOne      , &kSCPropNetPPPAuthPrompt                , NULL                , (void *)authPromptSelections   },
2011	{ "AuthProtocol"              , "protocol"    , isChooseMultiple , &kSCPropNetPPPAuthProtocol              , NULL                , (void *)authProtocolSelections },
2012
2013	// --- Comm: ---
2014	{ "CommRemoteAddress"         , "phone#"      , isString         , &kSCPropNetPPPCommRemoteAddress         , NULL                , NULL                           },
2015	{ "CommAlternateRemoteAddress", "phone#"      , isString         , &kSCPropNetPPPCommAlternateRemoteAddress, NULL                , NULL                           },
2016	{ "CommConnectDelay"          , "time"        , isNumber         , &kSCPropNetPPPCommConnectDelay          , NULL                , NULL                           },
2017	{ "CommDisplayTerminalWindow" , NULL          , isBoolean        , &kSCPropNetPPPCommDisplayTerminalWindow , NULL                , NULL                           },
2018	{ "CommRedialCount"           , "retry count" , isNumber         , &kSCPropNetPPPCommRedialCount           , NULL                , NULL                           },
2019	{ "CommRedialEnabled"         , NULL          , isBoolean        , &kSCPropNetPPPCommRedialEnabled         , NULL                , NULL                           },
2020	{ "CommRedialInterval"        , "retry delay" , isNumber         , &kSCPropNetPPPCommRedialInterval        , NULL                , NULL                           },
2021	{ "CommTerminalScript"        , "script"      , isString         , &kSCPropNetPPPCommTerminalScript        , NULL                , NULL                           },
2022	{ "CommUseTerminalScript"     , NULL          , isBoolean        , &kSCPropNetPPPCommUseTerminalScript     , NULL                , NULL                           },
2023
2024	// --- CCP: ---
2025	{ "CCPEnabled"                , NULL          , isBoolean        , &kSCPropNetPPPCCPEnabled                , NULL                , NULL                           },
2026	{ "CCPMPPE40Enabled"          , NULL          , isBoolean        , &kSCPropNetPPPCCPMPPE40Enabled          , NULL                , NULL                           },
2027	{ "CCPMPPE128Enabled"         , NULL          , isBoolean        , &kSCPropNetPPPCCPMPPE128Enabled         , NULL                , NULL                           },
2028
2029	// --- IPCP: ---
2030	{ "IPCPCompressionVJ"         , NULL          , isBoolean        , &kSCPropNetPPPIPCPCompressionVJ         , NULL                , NULL                           },
2031	{ "IPCPUsePeerDNS"            , NULL          , isBoolean        , &kSCPropNetPPPIPCPUsePeerDNS            , NULL                , NULL                           },
2032
2033	// --- LCP: ---
2034	{ "LCPEchoEnabled"            , NULL          , isBoolean        , &kSCPropNetPPPLCPEchoEnabled            , NULL                , NULL                           },
2035	{ "LCPEchoFailure"            , NULL          , isNumber         , &kSCPropNetPPPLCPEchoFailure            , NULL                , NULL                           },
2036	{ "LCPEchoInterval"           , NULL          , isNumber         , &kSCPropNetPPPLCPEchoInterval           , NULL                , NULL                           },
2037	{ "LCPCompressionACField"     , NULL          , isBoolean        , &kSCPropNetPPPLCPCompressionACField     , NULL                , NULL                           },
2038	{ "LCPCompressionPField"      , NULL          , isBoolean        , &kSCPropNetPPPLCPCompressionPField      , NULL                , NULL                           },
2039	{ "LCPMRU"                    , NULL          , isNumber         , &kSCPropNetPPPLCPMRU                    , NULL                , NULL                           },
2040	{ "LCPMTU"                    , NULL          , isNumber         , &kSCPropNetPPPLCPMTU                    , NULL                , NULL                           },
2041	{ "LCPReceiveACCM"            , NULL          , isNumber         , &kSCPropNetPPPLCPReceiveACCM            , NULL                , NULL                           },
2042	{ "LCPTransmitACCM"           , NULL          , isNumber         , &kSCPropNetPPPLCPTransmitACCM           , NULL                , NULL                           },
2043
2044	// --- IPSec: ---
2045	{ "IPSec"                     , NULL          , isOther          , NULL                                    , __doPPPIPSec        , NULL                           },
2046
2047#ifdef	NOTYET
2048	// --- OnDemand: ---
2049	{ "OnDemandEnabled"            , NULL         , isBoolean        , &kSCPropNetPPPOnDemandEnabled           , NULL                , NULL },
2050	{ "OnDemandMatch"              , NULL         , isOther          , NULL                                    , __doPPPOnDemandMatch, NULL },
2051#endif	// NOTYET
2052
2053	// --- Help ---
2054	{ "?"                         , NULL          , isHelp           , NULL                                    , NULL                ,
2055	    "\nPPP configuration commands\n\n"
2056	    " set interface [Account account]\n"
2057	    " set interface [Password password]\n"
2058	    " set interface [Number telephone-number]\n"
2059	    " set interface [AlternateNumber telephone-number]\n"
2060	    " set interface [IdleReminder {enable|disable}]\n"
2061	    " set interface [IdleReminderTimer time-in-seconds]\n"
2062	    " set interface [DisconnectOnIdle {enable|disable}]\n"
2063	    " set interface [DisconnectOnIdleTimer time-in-seconds]\n"
2064	    " set interface [DisconnectOnLogout {enable|disable}]\n"
2065	    " set interface [IPSec <ipsec-options>]\n"
2066#ifdef	NOTYET
2067	    " set interface [OnDemandEnabled {enable|disable}]\n"
2068	    " set interface [OnDemandMatch <match-options>]\n"
2069#endif	// NOTYET
2070	}
2071};
2072#define	N_PPP_OPTIONS	(sizeof(pppOptions) / sizeof(pppOptions[0]))
2073
2074
2075static Boolean
2076set_interface_ppp(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2077{
2078	Boolean	ok;
2079
2080	ok = _process_options(pppOptions, N_PPP_OPTIONS, argc, argv, newConfiguration);
2081	return ok;
2082}
2083
2084
2085#pragma mark -
2086#pragma mark VLAN options
2087
2088
2089static Boolean
2090set_interface_vlan(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2091{
2092// xxxxx ("device", "tag")
2093SCPrint(TRUE, stdout, CFSTR("vlan interface management not yet supported\n"));
2094	return FALSE;
2095}
2096
2097
2098#pragma mark -
2099#pragma mark VPN options
2100
2101
2102static int
2103__doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2104{
2105	CFStringRef	encryptionType;
2106
2107	if (argc < 1) {
2108		SCPrint(TRUE, stdout, CFSTR("VPN password not specified\n"));
2109		return -1;
2110	}
2111
2112	encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption);
2113	if (strlen(argv[0]) > 0) {
2114		if (encryptionType == NULL) {
2115#ifdef	INLINE_PASSWORDS_USE_CFSTRING
2116			CFStringRef		pw;
2117
2118			pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
2119#else	// INLINE_PASSWORDS_USE_CFSTRING
2120			CFIndex			n;
2121			CFMutableDataRef	pw;
2122			CFStringRef		str;
2123
2124			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
2125			n = CFStringGetLength(str);
2126			pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
2127			CFDataSetLength(pw, n * sizeof(UniChar));
2128			CFStringGetCharacters(str,
2129					      CFRangeMake(0, n),
2130					      (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
2131			CFRelease(str);
2132#endif	// INLINE_PASSWORDS_USE_CFSTRING
2133
2134			CFDictionarySetValue(newConfiguration, key, pw);
2135			CFRelease(pw);
2136		} else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
2137			Boolean		ok;
2138			CFDataRef	pw;
2139			CFStringRef	str;
2140
2141			str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
2142			pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
2143			ok = SCNetworkInterfaceSetPassword(net_interface,
2144							   kSCNetworkInterfacePasswordTypeVPN,
2145							   pw,
2146							   NULL);
2147			CFRelease(pw);
2148			CFRelease(str);
2149			if (ok) {
2150				updateInterfaceConfiguration(newConfiguration);
2151			} else {
2152				return -1;
2153			}
2154		} else {
2155			SCPrint(TRUE, stdout, CFSTR("VPN password type \"%@\" not supported\n"), encryptionType);
2156			return -1;
2157		}
2158	} else {
2159		if (encryptionType == NULL) {
2160			CFDictionaryRemoveValue(newConfiguration, key);
2161		} else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
2162			Boolean		ok;
2163
2164			ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeVPN);
2165			if (ok) {
2166				updateInterfaceConfiguration(newConfiguration);
2167			} else {
2168				return -1;
2169			}
2170		} else {
2171			SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
2172			return -1;
2173		}
2174	}
2175
2176	return 1;
2177}
2178
2179
2180static int
2181__doVPNAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2182{
2183	if (argc < 1) {
2184		SCPrint(TRUE, stdout, CFSTR("VPN password type mode not specified\n"));
2185		return -1;
2186	}
2187
2188	if (strlen(argv[0]) > 0) {
2189		if (strcasecmp(argv[0], "keychain") == 0) {
2190			CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionKeychain);
2191		} else if (strcasecmp(argv[0], "prompt") == 0) {
2192			CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionPrompt);
2193		} else {
2194			SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
2195			return -1;
2196		}
2197	} else {
2198		CFDictionaryRemoveValue(newConfiguration, key);
2199	}
2200
2201	// encryption type changed, reset password
2202	CFDictionaryRemoveValue(newConfiguration, kSCPropNetVPNAuthPassword);
2203
2204	return 1;
2205}
2206
2207
2208static selections vpnAuthenticationMethodSelections[] = {
2209	{ CFSTR("Password")    , &kSCValNetVPNAuthenticationMethodPassword    , 0 },
2210	{ CFSTR("Certificate") , &kSCValNetVPNAuthenticationMethodCertificate , 0 },
2211	{ NULL                 , NULL                                         , 0 }
2212};
2213
2214
2215static options vpnOptions[] = {
2216	{ "AuthName"                  , "account"     , isString     , &kSCPropNetVPNAuthName                  , NULL                , NULL                                      },
2217	{   "Account"                 , "account"     , isString     , &kSCPropNetVPNAuthName                  , NULL                , NULL                                      },
2218	{ "AuthPassword"              , "password"    , isOther      , &kSCPropNetVPNAuthPassword              , __doVPNAuthPW       , NULL                                      },
2219	{   "Password"                , "password"    , isOther      , &kSCPropNetVPNAuthPassword              , __doVPNAuthPW       , NULL                                      },
2220	{ "AuthPasswordEncryption"    , "type"        , isOther      , &kSCPropNetVPNAuthPasswordEncryption    , __doVPNAuthPWType   , NULL                                      },
2221	{ "AuthenticationMethod"      , NULL          , isChooseOne  , &kSCPropNetVPNAuthenticationMethod      , NULL                , (void *)vpnAuthenticationMethodSelections },
2222	{ "ConnectTime"               , "?time"       , isNumber     , &kSCPropNetVPNConnectTime               , NULL                , NULL                                      },
2223	{ "DisconnectOnFastUserSwitch", NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnFastUserSwitch, NULL                , NULL                                      },
2224	{ "DisconnectOnIdle"          , NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnIdle          , NULL                , NULL                                      },
2225	{ "DisconnectOnIdleTimer"     , "timeout"     , isNumber     , &kSCPropNetVPNDisconnectOnIdleTimer     , NULL                , NULL                                      },
2226	{ "DisconnectOnLogout"        , NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnLogout        , NULL                , NULL                                      },
2227	{ "DisconnectOnSleep"         , NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnSleep         , NULL                , NULL                                      },
2228	{ "Logfile"                   , "path"        , isString     , &kSCPropNetVPNLogfile                   , NULL                , NULL                                      },
2229	{ "MTU"                       , NULL          , isNumber     , &kSCPropNetVPNMTU                       , NULL                , NULL                                      },
2230	{ "RemoteAddress"             , "server"      , isString     , &kSCPropNetVPNRemoteAddress             , NULL                , NULL                                      },
2231	{   "Server"                  , "server"      , isString     , &kSCPropNetVPNRemoteAddress             , NULL                , NULL                                      },
2232	{ "VerboseLogging"            , NULL          , isBoolean    , &kSCPropNetVPNVerboseLogging            , NULL                , NULL                                      },
2233
2234	// --- Help ---
2235	{ "?"                         , NULL          , isHelp       , NULL                                    , NULL                ,
2236	    "\nVPN configuration commands\n\n"
2237	    " set interface [Server server]\n"
2238	    " set interface [Account account]\n"
2239	    " set interface [Password password]\n"
2240	}
2241};
2242#define	N_VPN_OPTIONS	(sizeof(vpnOptions) / sizeof(vpnOptions[0]))
2243
2244
2245static Boolean
2246set_interface_vpn(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2247{
2248	Boolean	ok;
2249
2250	ok = _process_options(vpnOptions, N_VPN_OPTIONS, argc, argv, newConfiguration);
2251	return ok;
2252}
2253
2254
2255#pragma mark -
2256#pragma mark [more] Interface management
2257
2258
2259__private_extern__
2260void
2261set_interface(int argc, char **argv)
2262{
2263	CFDictionaryRef		configuration;
2264	CFStringRef		interfaceType;
2265	CFMutableDictionaryRef	newConfiguration	= NULL;
2266	Boolean			ok			= FALSE;
2267
2268	if (net_interface == NULL) {
2269		SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
2270		return;
2271	}
2272
2273	if (argc < 1) {
2274		SCPrint(TRUE, stdout, CFSTR("set what?\n"));
2275		return;
2276	}
2277
2278	configuration = SCNetworkInterfaceGetConfiguration(net_interface);
2279	if (configuration != NULL) {
2280		configuration = CFDictionaryCreateCopy(NULL, configuration);
2281		newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
2282		CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
2283	} else {
2284		newConfiguration = CFDictionaryCreateMutable(NULL,
2285							     0,
2286							     &kCFTypeDictionaryKeyCallBacks,
2287							     &kCFTypeDictionaryValueCallBacks);
2288	}
2289
2290	interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
2291
2292	if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet)) {
2293		ok = set_interface_ethernet(argc, argv, newConfiguration);
2294	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeFireWire)) {
2295		ok = set_interface_firewire(argc, argv, newConfiguration);
2296	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
2297		ok = set_interface_ipsec(argc, argv, newConfiguration);
2298	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeModem)) {
2299		ok = set_interface_modem(argc, argv, newConfiguration);
2300	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIEEE80211)) {
2301		ok = set_interface_airport(argc, argv, newConfiguration);
2302	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2303		ok = set_interface_ppp(argc, argv, newConfiguration);
2304	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
2305		ok = set_interface_bond(argc, argv, newConfiguration);
2306	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
2307		ok = set_interface_bridge(argc, argv, newConfiguration);
2308	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
2309		ok = set_interface_vlan(argc, argv, newConfiguration);
2310	} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
2311		ok = set_interface_vpn(argc, argv, newConfiguration);
2312	} else {
2313		SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
2314	}
2315
2316	if (!ok) {
2317		goto done;
2318	}
2319
2320	if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
2321	    ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
2322		if (!SCNetworkInterfaceSetConfiguration(net_interface, newConfiguration)) {
2323			if (SCError() == kSCStatusNoKey) {
2324				SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n"));
2325			} else {
2326				SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
2327			}
2328			goto done;
2329		}
2330
2331		_prefs_changed = TRUE;
2332	}
2333
2334    done :
2335
2336	if (configuration != NULL) CFRelease(configuration);
2337	if (newConfiguration != NULL) CFRelease(newConfiguration);
2338	return;
2339}
2340
2341
2342/* -------------------- */
2343
2344
2345__private_extern__
2346void
2347show_interface(int argc, char **argv)
2348{
2349	SCNetworkInterfaceRef	interface;
2350
2351	if (argc >= 1) {
2352		interface = _find_interface(argc, argv, NULL);
2353	} else {
2354		if (net_interface != NULL) {
2355			interface = net_interface;
2356		} else {
2357			SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
2358			return;
2359		}
2360	}
2361
2362	if (interface != NULL) {
2363		_show_interface(interface, CFSTR(""), TRUE);
2364	}
2365
2366	return;
2367}
2368
2369
2370/* -------------------- */
2371
2372
2373__private_extern__
2374CF_RETURNS_RETAINED CFStringRef
2375_interface_description(SCNetworkInterfaceRef interface)
2376{
2377	CFMutableStringRef	description;
2378	CFStringRef		if_bsd_name;
2379	CFStringRef		if_type;
2380
2381	description = CFStringCreateMutable(NULL, 0);
2382
2383	if_type = SCNetworkInterfaceGetInterfaceType(interface);
2384	CFStringAppend(description, if_type);
2385
2386	if_bsd_name = SCNetworkInterfaceGetBSDName(interface);
2387	if (if_bsd_name != NULL) {
2388		CFStringAppendFormat(description, NULL, CFSTR(" (%@)"), if_bsd_name);
2389	}
2390
2391	interface = SCNetworkInterfaceGetInterface(interface);
2392	while ((interface != NULL) &&
2393	       !CFEqual(interface, kSCNetworkInterfaceIPv4)) {
2394		CFStringRef	childDescription;
2395
2396		childDescription = _interface_description(interface);
2397		CFStringAppendFormat(description, NULL, CFSTR(" / %@"), childDescription);
2398		CFRelease(childDescription);
2399
2400		interface = SCNetworkInterfaceGetInterface(interface);
2401	}
2402
2403	return description;
2404}
2405