]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/net_interface.c
a7bb46c57eee502f3eb4156e66c7af3b7df9f632
[apple/configd.git] / scutil.tproj / net_interface.c
1 /*
2 * Copyright (c) 2004 Apple Computer, 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 "scutil.h"
33 #include "net.h"
34
35 #include <SystemConfiguration/LinkConfiguration.h>
36
37
38 /* -------------------- */
39
40
41 static CFArrayRef
42 _copy_interfaces()
43 {
44 CFMutableArrayRef interfaces;
45 CFArrayRef real_interfaces;
46
47 real_interfaces = SCNetworkInterfaceCopyAll();
48 if (real_interfaces == NULL) {
49 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
50 return NULL;
51 }
52
53 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
54
55 // include real interfaces
56 CFArrayAppendArray(interfaces,
57 real_interfaces,
58 CFRangeMake(0, CFArrayGetCount(real_interfaces)));
59 CFRelease(real_interfaces);
60
61 // include pseudo interfaces
62 CFArrayAppendValue(interfaces, kSCNetworkInterfaceIPv4);
63
64 // include interfaces that we have created
65 if (new_interfaces != NULL) {
66 CFArrayAppendArray(interfaces,
67 new_interfaces,
68 CFRangeMake(0, CFArrayGetCount(new_interfaces)));
69 }
70
71 return (CFArrayRef)interfaces;
72 }
73
74
75 __private_extern__
76 SCNetworkInterfaceRef
77 _find_interface(char *match)
78 {
79 Boolean allowIndex = TRUE;
80 CFIndex i;
81 CFIndex n;
82 CFStringRef select_name = NULL;
83 SCNetworkInterfaceRef selected = NULL;
84
85 if (strcasecmp(match, "$child") == 0) {
86 if (net_interface == NULL) {
87 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
88 goto done;
89 }
90
91 selected = SCNetworkInterfaceGetInterface(net_interface);
92 if(selected == NULL) {
93 SCPrint(TRUE, stdout, CFSTR("no child interface\n"));
94 }
95
96 goto done;
97 } else if (strcasecmp(match, "$service") == 0) {
98 if (net_service == NULL) {
99 SCPrint(TRUE, stdout, CFSTR("service not selected\n"));
100 goto done;
101 }
102
103 selected = SCNetworkServiceGetInterface(net_service);
104 if(selected == NULL) {
105 SCPrint(TRUE, stdout, CFSTR("no interface for service\n"));
106 }
107
108 goto done;
109 }
110
111 if (interfaces == NULL) {
112 interfaces = _copy_interfaces();
113 if (interfaces == NULL) {
114 return NULL;
115 }
116 allowIndex = FALSE;
117 }
118
119 // try to select the interface by its display name
120
121 select_name = CFStringCreateWithCString(NULL, match, kCFStringEncodingUTF8);
122
123 n = CFArrayGetCount(interfaces);
124 for (i = 0; i < n; i++) {
125 SCNetworkInterfaceRef interface;
126 CFStringRef interfaceName;
127
128 interface = CFArrayGetValueAtIndex(interfaces, i);
129 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
130 if ((interfaceName != NULL) && CFEqual(select_name, interfaceName)) {
131 if (selected == NULL) {
132 selected = interface;
133 } else {
134 // if multiple interfaces match
135 selected = NULL;
136 SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
137 goto done;
138 }
139 }
140 }
141
142 if (selected != NULL) {
143 goto done;
144 }
145
146 // try to select the interface by its BSD name
147
148 for (i = 0; i < n; i++) {
149 SCNetworkInterfaceRef interface;
150 CFStringRef bsd_name = NULL;
151
152 interface = CFArrayGetValueAtIndex(interfaces, i);
153 while ((interface != NULL) && (bsd_name == NULL)) {
154 bsd_name = SCNetworkInterfaceGetBSDName(interface);
155 if (bsd_name == NULL) {
156 interface = SCNetworkInterfaceGetInterface(interface);
157 }
158 }
159
160 if ((bsd_name != NULL) && CFEqual(select_name, bsd_name)) {
161 if (selected == NULL) {
162 selected = interface;
163 } else {
164 // if multiple interfaces match
165 selected = NULL;
166 SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
167 goto done;
168 }
169 }
170 }
171
172 if (selected != NULL) {
173 goto done;
174 }
175
176 // try to select the interface by its interface type
177
178 for (i = 0; i < n; i++) {
179 SCNetworkInterfaceRef interface;
180 CFStringRef interfaceType;
181
182 interface = CFArrayGetValueAtIndex(interfaces, i);
183 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
184 if (CFEqual(select_name, interfaceType)) {
185 if (selected == NULL) {
186 selected = interface;
187 } else {
188 // if multiple interfaces match
189 selected = NULL;
190 SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
191 goto done;
192 }
193 }
194 }
195
196 if (selected != NULL) {
197 goto done;
198 }
199
200 if (allowIndex) {
201 char *end;
202 char *str = match;
203 long val;
204
205 // try to select the interface by its index
206
207 errno = 0;
208 val = strtol(str, &end, 10);
209 if ((*str != '\0') &&
210 ((*end == '\0') || (*end == '.')) &&
211 (errno == 0)) {
212 if ((val > 0) && (val <= n)) {
213 selected = CFArrayGetValueAtIndex(interfaces, val - 1);
214
215 if (*end == '.') {
216 str = end + 1;
217 val = strtol(str, &end, 10);
218 if ((*str != '\0') && (*end == '\0') && (errno == 0)) {
219 while (val-- > 0) {
220 selected = SCNetworkInterfaceGetInterface(selected);
221 if (selected == NULL) {
222 break;
223 }
224 }
225 }
226 }
227 }
228 }
229 }
230
231 if (selected != NULL) {
232 goto done;
233 }
234
235 SCPrint(TRUE, stdout, CFSTR("no match\n"));
236
237 done :
238
239 if (select_name != NULL) CFRelease(select_name);
240 return selected;
241 }
242
243
244 /* -------------------- */
245
246
247 __private_extern__
248 void
249 create_interface(int argc, char **argv)
250 {
251 SCNetworkInterfaceRef interface;
252 CFStringRef interfaceName;
253 CFStringRef interfaceType;
254 SCNetworkInterfaceRef new_interface;
255
256 if (argc < 1) {
257 SCPrint(TRUE, stdout, CFSTR("what interface type?\n"));
258 return;
259 }
260
261 interfaceType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
262
263 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
264 // xxxxx
265 SCPrint(TRUE, stdout, CFSTR("vlan creation not yet supported\n"));
266 goto done;
267 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
268 // xxxxx
269 SCPrint(TRUE, stdout, CFSTR("bond creation not yet supported\n"));
270 goto done;
271 } else {
272 if (argc < 2) {
273 if (net_interface == NULL) {
274 SCPrint(TRUE, stdout, CFSTR("no network interface selected\n"));
275 goto done;
276 }
277
278 interface = net_interface;
279 } else {
280 interface = _find_interface(argv[1]);
281 }
282
283 if (interface == NULL) {
284 return;
285 }
286
287 new_interface = SCNetworkInterfaceCreateWithInterface(interface, interfaceType);
288 if (new_interface == NULL) {
289 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
290 goto done;
291 }
292 }
293
294 if (new_interfaces == NULL) {
295 new_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
296 }
297 CFArrayAppendValue(new_interfaces, new_interface);
298
299 if (net_interface != NULL) CFRelease(net_interface);
300 net_interface = new_interface;
301
302 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(net_interface);
303 if (interfaceName == NULL) {
304 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
305 }
306 if (interfaceName == NULL) {
307 interfaceName = SCNetworkInterfaceGetInterfaceType(net_interface);
308 }
309 SCPrint(TRUE, stdout, CFSTR("interface \"%@\" created and selected\n"), interfaceName);
310
311 done :
312
313 CFRelease(interfaceType);
314 return;
315 }
316
317
318 /* -------------------- */
319
320
321 __private_extern__
322 void
323 select_interface(int argc, char **argv)
324 {
325 SCNetworkInterfaceRef interface;
326
327 interface = _find_interface(argv[0]);
328
329 if (interface != NULL) {
330 CFStringRef interfaceName;
331
332 if (net_interface != NULL) CFRelease(net_interface);
333 net_interface = CFRetain(interface);
334
335 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
336 if (interfaceName == NULL) {
337 interfaceName = SCNetworkInterfaceGetBSDName(interface);
338 }
339 if (interfaceName == NULL) {
340 interfaceName = SCNetworkInterfaceGetInterfaceType(interface);
341 }
342
343 SCPrint(TRUE, stdout, CFSTR("interface \"%@\" selected\n"), interfaceName);
344 }
345
346 return;
347 }
348
349
350 /* -------------------- */
351
352
353 __private_extern__
354 void
355 _show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean showChild)
356 {
357 CFDictionaryRef configuration;
358 CFStringRef if_bsd_name;
359 CFStringRef if_localized_name;
360 CFStringRef if_mac_address;
361 CFStringRef if_type;
362 CFArrayRef supported;
363
364 if_localized_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
365 if (if_localized_name != NULL) {
366 SCPrint(TRUE, stdout, CFSTR("%@ name = %@\n"), prefix, if_localized_name);
367 }
368
369 if_bsd_name = SCNetworkInterfaceGetBSDName(interface);
370 if (if_bsd_name != NULL) {
371 SCPrint(TRUE, stdout, CFSTR("%@ interface name = %@\n"), prefix, if_bsd_name);
372 }
373
374 if_type = SCNetworkInterfaceGetInterfaceType(interface);
375 SCPrint(TRUE, stdout, CFSTR("%@ type = %@\n"), prefix, if_type);
376
377 if_mac_address = SCNetworkInterfaceGetHardwareAddressString(interface);
378 if (if_mac_address != NULL) {
379 SCPrint(TRUE, stdout, CFSTR("%@ address = %@\n"), prefix, if_mac_address);
380 }
381
382 configuration = SCNetworkInterfaceGetConfiguration(interface);
383 if ((configuration != NULL) &&
384 CFDictionaryContainsKey(configuration, kSCResvInactive)) {
385 configuration = NULL;
386 }
387
388 if (if_bsd_name != NULL) {
389 CFArrayRef available;
390 CFDictionaryRef active;
391 int mtu_cur;
392 int mtu_min;
393 int mtu_max;
394
395 if (NetworkInterfaceCopyMTU(if_bsd_name, &mtu_cur, &mtu_min, &mtu_max)) {
396 char isCurrent = '*';
397
398 if (configuration != NULL) {
399 int mtu_req;
400 CFNumberRef num;
401
402 num = CFDictionaryGetValue(configuration, kSCPropNetEthernetMTU);
403 if (isA_CFNumber(num)) {
404 CFNumberGetValue(num, kCFNumberIntType, &mtu_req);
405 if (mtu_cur != mtu_req) {
406 mtu_cur = mtu_req;
407 isCurrent = ' ';
408 }
409 }
410 }
411
412 SCPrint(TRUE, stdout, CFSTR("%@ mtu %c = %ld (%ld < n < %ld)\n"),
413 prefix,
414 isCurrent,
415 mtu_cur,
416 mtu_min,
417 mtu_max);
418 }
419
420 if (NetworkInterfaceCopyMediaOptions(if_bsd_name, NULL, &active, &available, TRUE)) {
421 char isCurrent = ' ';
422 CFArrayRef options = NULL;
423 CFArrayRef options_req = NULL;
424 CFStringRef subtype = NULL;
425 CFStringRef subtype_req = NULL;
426
427 if (configuration != NULL) {
428 subtype_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaSubType);
429 options_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaOptions);
430 }
431
432 if (subtype_req == NULL) {
433 subtype_req = CFSTR("autoselect");
434 }
435
436 if (active != NULL) {
437 subtype = CFDictionaryGetValue(active, kSCPropNetEthernetMediaSubType);
438 options = CFDictionaryGetValue(active, kSCPropNetEthernetMediaOptions);
439 }
440
441 if (subtype != NULL) {
442 if (((subtype_req != NULL) &&
443 CFEqual(subtype, subtype_req)) &&
444 ((options == options_req) ||
445 ((options != NULL) &&
446 (options_req != NULL) &&
447 CFEqual(options, options_req)))
448 ) {
449 isCurrent = '*';
450 } else if ((subtype_req == NULL) ||
451 ((subtype_req != NULL) &&
452 CFEqual(subtype_req, CFSTR("autoselect")))) {
453 // if requested subtype not specified or "autoselect"
454 isCurrent = '*';
455 }
456 }
457
458 if (subtype_req != NULL) {
459 SCPrint(TRUE, stdout, CFSTR("%@ media %c = %@"),
460 prefix,
461 isCurrent,
462 subtype_req);
463
464 if ((options_req != NULL) &&
465 (CFArrayGetCount(options_req) > 0)) {
466 CFStringRef options_str;
467
468 options_str = CFStringCreateByCombiningStrings(NULL, options_req, CFSTR(","));
469 SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str);
470 CFRelease(options_str);
471 }
472
473 SCPrint(TRUE, stdout, CFSTR("\n"));
474 }
475
476 SCPrint(TRUE, stdout, CFSTR("\n"));
477
478 if (available != NULL) {
479 CFIndex i;
480 CFIndex n_subtypes;
481 CFArrayRef subtypes;
482
483 subtypes = NetworkInterfaceCopyMediaSubTypes(available);
484 n_subtypes = (subtypes != NULL) ? CFArrayGetCount(subtypes) : 0;
485 for (i = 0; i < n_subtypes; i++) {
486 CFIndex j;
487 CFIndex n_subtype_options;
488 CFStringRef subtype;
489 CFArrayRef subtype_options;
490
491 subtype = CFArrayGetValueAtIndex(subtypes, i);
492 subtype_options = NetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
493 n_subtype_options = (subtype_options != NULL) ? CFArrayGetCount(subtype_options) : 0;
494 for (j = 0; j < n_subtype_options; j++) {
495 char isCurrent = ' ';
496 CFArrayRef options;
497
498 options = CFArrayGetValueAtIndex(subtype_options, j);
499
500 if (((subtype_req != NULL) &&
501 CFEqual(subtype, subtype_req)) &&
502 ((options == options_req) ||
503 ((options != NULL) &&
504 (options_req != NULL) &&
505 CFEqual(options, options_req)))
506 ) {
507 isCurrent = '*';
508 }
509
510 SCPrint(TRUE, stdout, CFSTR("%@ %s %c = %@"),
511 prefix,
512 ((i == 0) && (j == 0)) ? "supported media" : " ",
513 isCurrent,
514 subtype);
515
516 if ((options != NULL) &&
517 (CFArrayGetCount(options) > 0)) {
518 CFStringRef options_str;
519
520 options_str = CFStringCreateByCombiningStrings(NULL, options, CFSTR(","));
521 SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str);
522 CFRelease(options_str);
523 }
524
525 SCPrint(TRUE, stdout, CFSTR("\n"));
526 }
527 CFRelease(subtype_options);
528 }
529 }
530 } else {
531 SCPrint(TRUE, stdout, CFSTR("\n"));
532 }
533 }
534
535 supported = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
536 SCPrint(TRUE, stdout, CFSTR("%@ supported interfaces = "), prefix);
537 if (supported != NULL) {
538 CFIndex i;
539 CFIndex n = CFArrayGetCount(supported);
540
541 for (i = 0; i < n; i++) {
542 SCPrint(TRUE, stdout, CFSTR("%s%@"),
543 (i == 0) ? "" : ", ",
544 CFArrayGetValueAtIndex(supported, i));
545 }
546 }
547 SCPrint(TRUE, stdout, CFSTR("\n"));
548
549 supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
550 SCPrint(TRUE, stdout, CFSTR("%@ supported protocols = "), prefix);
551 if (supported != NULL) {
552 CFIndex i;
553 CFIndex n = CFArrayGetCount(supported);
554
555 for (i = 0; i < n; i++) {
556 SCPrint(TRUE, stdout, CFSTR("%s%@"),
557 (i == 0) ? "" : ", ",
558 CFArrayGetValueAtIndex(supported, i));
559 }
560 }
561 SCPrint(TRUE, stdout, CFSTR("\n"));
562
563 if (configuration != NULL) {
564 CFMutableDictionaryRef effective;
565
566 effective = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
567
568 // remove known (and already reported) interface configuration keys
569 if (CFDictionaryContainsKey(effective, kSCResvInactive)) {
570 CFDictionaryRemoveAllValues(effective);
571 }
572 CFDictionaryRemoveValue(effective, kSCPropNetEthernetMTU);
573 CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaSubType);
574 CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaOptions);
575
576 if (CFDictionaryGetCount(effective) > 0) {
577 SCPrint(TRUE, stdout, CFSTR("\n%@ per-interface configuration\n"), prefix);
578 _show_entity(configuration, prefix);
579 }
580
581 CFRelease(effective);
582 }
583
584 if (_sc_debug) {
585 SCPrint(TRUE, stdout, CFSTR("\n%@\n"), interface);
586 }
587
588 interface = SCNetworkInterfaceGetInterface(interface);
589 if (interface != NULL) {
590 CFStringRef newPrefix;
591
592 newPrefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ "), prefix);
593 SCPrint(TRUE, stdout, CFSTR("\n%@child interface\n"), newPrefix);
594 _show_interface(interface, newPrefix, showChild);
595 CFRelease(newPrefix);
596 }
597
598 return;
599 }
600
601
602 /* -------------------- */
603
604
605 __private_extern__
606 void
607 show_interfaces(int argc, char **argv)
608 {
609 CFIndex i;
610 CFIndex n;
611
612 if (interfaces != NULL) CFRelease(interfaces);
613 interfaces = _copy_interfaces();
614 if (interfaces == NULL) {
615 return;
616 }
617
618 n = CFArrayGetCount(interfaces);
619 for (i = 0; i < n; i++) {
620 CFIndex childIndex = 0;
621 SCNetworkInterfaceRef interface;
622
623 interface = CFArrayGetValueAtIndex(interfaces, i);
624 do {
625 CFStringRef interfaceName;
626 char isSelected;
627
628 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
629 if (interfaceName == NULL) {
630 interfaceName = SCNetworkInterfaceGetBSDName(interface);
631 }
632 if (interfaceName == NULL) {
633 interfaceName = SCNetworkInterfaceGetInterfaceType(interface);
634 }
635
636 isSelected = ' ';
637 if ((net_interface != NULL) && CFEqual(interface, net_interface)) {
638 isSelected = '>';
639 }
640
641 if (childIndex == 0) {
642 SCPrint(TRUE, stdout, CFSTR("%c%2d: %@\n"),
643 isSelected,
644 i + 1,
645 interfaceName);
646 } else {
647 SCPrint(TRUE, stdout, CFSTR("%c%2d.%d: %@\n"),
648 isSelected,
649 i + 1,
650 childIndex,
651 interfaceName);
652 }
653
654 interface = SCNetworkInterfaceGetInterface(interface);
655 childIndex++;
656 } while (interface != NULL);
657 }
658
659 return;
660 }
661
662
663 /* -------------------- */
664
665
666 static Boolean
667 set_interface_bond(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
668 {
669 // xxxxx ("+device", "-device")
670 SCPrint(TRUE, stdout, CFSTR("bond interface management not yet supported\n"));
671 return FALSE;
672 }
673
674
675 /* -------------------- */
676
677
678 static Boolean
679 set_interface_airport(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
680 {
681 SCPrint(TRUE, stdout, CFSTR("airport interface management not yet supported\n"));
682 return FALSE;
683 }
684
685
686 /* -------------------- */
687
688
689 static options ethernetOptions[] = {
690 { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL },
691 { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL },
692 { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
693
694 { "?" , NULL , isHelp , NULL , NULL,
695 "\nEthernet configuration commands\n\n"
696 " set interface [mtu n] [media type] [mediaopts opts]\n"
697 }
698 };
699 #define N_ETHERNET_OPTIONS (sizeof(ethernetOptions) / sizeof(ethernetOptions[0]))
700
701
702 static Boolean
703 set_interface_ethernet(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
704 {
705 CFStringRef interfaceName;
706 Boolean ok;
707
708 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
709 if (interfaceName == NULL) {
710 SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
711 return FALSE;
712 }
713
714 ok = _process_options(ethernetOptions, N_ETHERNET_OPTIONS, argc, argv, newConfiguration);
715 if (ok) {
716 CFNumberRef mtu;
717 CFArrayRef options;
718 CFStringRef subtype;
719
720 // validate configuration
721
722 mtu = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMTU);
723 if (isA_CFNumber(mtu)) {
724 int mtu_max;
725 int mtu_min;
726 int mtu_val;
727
728 if (!NetworkInterfaceCopyMTU(interfaceName, NULL, &mtu_min, &mtu_max)) {
729 SCPrint(TRUE, stdout, CFSTR("cannot set MTU\n"));
730 return FALSE;
731 }
732
733 if (!CFNumberGetValue(mtu, kCFNumberIntType, &mtu_val) ||
734 (mtu_val < mtu_min) ||
735 (mtu_val > mtu_max)) {
736 SCPrint(TRUE, stdout, CFSTR("mtu out of range\n"));
737 return FALSE;
738 }
739 }
740
741 subtype = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaSubType);
742 options = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaOptions);
743
744 if (subtype != NULL) {
745 CFArrayRef available = NULL;
746 CFArrayRef config_options = options;
747 CFArrayRef subtypes = NULL;
748 CFArrayRef subtype_options = NULL;
749
750 ok = FALSE;
751
752 if (options == NULL) {
753 config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
754 }
755
756 if (interfaceName == NULL) {
757 SCPrint(TRUE, stdout, CFSTR("media type / options not available\n"));
758 goto checked;
759 }
760
761 if (!NetworkInterfaceCopyMediaOptions(interfaceName, NULL, NULL, &available, FALSE)) {
762 SCPrint(TRUE, stdout, CFSTR("media type / options not available\n"));
763 goto checked;
764 }
765
766 if (available == NULL) {
767 goto checked;
768 }
769
770 subtypes = NetworkInterfaceCopyMediaSubTypes(available);
771 if ((subtypes == NULL) ||
772 !CFArrayContainsValue(subtypes,
773 CFRangeMake(0, CFArrayGetCount(subtypes)),
774 subtype)) {
775 SCPrint(TRUE, stdout, CFSTR("media type not valid\n"));
776 goto checked;
777 }
778
779 subtype_options = NetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
780 if ((subtype_options == NULL) ||
781 !CFArrayContainsValue(subtype_options,
782 CFRangeMake(0, CFArrayGetCount(subtype_options)),
783 config_options)) {
784 SCPrint(TRUE, stdout, CFSTR("media options not valid for \"%@\"\n"), subtype);
785 goto checked;
786 }
787
788 if (options == NULL) {
789 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaOptions, config_options);
790 }
791
792 ok = TRUE;
793
794 checked :
795
796 if (available != NULL) CFRelease(available);
797 if (subtypes != NULL) CFRelease(subtypes);
798 if (subtype_options != NULL) CFRelease(subtype_options);
799 if (options == NULL) CFRelease(config_options);
800 } else {
801 if (options != NULL) {
802 SCPrint(TRUE, stdout, CFSTR("media type and options must both be specified\n"));
803 return FALSE;
804 }
805 }
806 }
807
808 return ok;
809 }
810
811
812 /* -------------------- */
813
814
815 static selections modemDialSelections[] = {
816 { CFSTR("ignore"), &kSCValNetModemDialModeIgnoreDialTone , 0 },
817 { CFSTR("manual"), &kSCValNetModemDialModeManual , 0 },
818 { CFSTR("wait") , &kSCValNetModemDialModeWaitForDialTone, 0 },
819 { NULL , NULL , 0 }
820 };
821
822 static options modemOptions[] = {
823 { "ConnectionScript" , "script", isString , &kSCPropNetModemConnectionScript , NULL, NULL },
824 { "DialMode" , "mode" , isChooseOne, &kSCPropNetModemDialMode , NULL, (void *)modemDialSelections },
825 { "CallWaiting" , NULL , isBoolean , &kSCPropNetModemHoldEnabled , NULL, NULL },
826 { "CallWaitingAlert" , NULL , isBoolean , &kSCPropNetModemHoldCallWaitingAudibleAlert, NULL, NULL },
827 { "CallWaitingDisconnectOnAnswer", NULL , isBoolean , &kSCPropNetModemHoldDisconnectOnAnswer , NULL, NULL },
828 { "DataCompression" , NULL , isBoolean , &kSCPropNetModemDataCompression , NULL, NULL },
829 { "ErrorCorrection" , NULL , isBoolean , &kSCPropNetModemErrorCorrection , NULL, NULL },
830 { "HoldReminder" , NULL , isBoolean , &kSCPropNetModemHoldReminder , NULL, NULL },
831 { "HoldReminderTime" , "time" , isNumber , &kSCPropNetModemHoldReminderTime , NULL, NULL },
832 { "PulseDial" , NULL , isBoolean , &kSCPropNetModemPulseDial , NULL, NULL },
833 { "Speaker" , NULL , isBoolean , &kSCPropNetModemSpeaker , NULL, NULL },
834
835 { "?" , NULL , isHelp , NULL , NULL,
836 "\nModem configuration commands\n\n"
837 " set interface [ConnectionScript connection-script]\n"
838 " set interface [CallWaiting {enable|disable}]\n"
839 " set interface [CallWaitingAlert {enable|disable}]\n"
840 " set interface [CallWaitingDisconnectOnAnswer {enable|disable}]\n"
841 " set interface [DialMode {ignore|wait}]\n"
842 " set interface [DataCompression {enable|disable}]\n"
843 " set interface [ErrorCorrection {enable|disable}]\n"
844 " set interface [HoldReminder {enable|disable}]\n"
845 " set interface [HoldReminderTime n]\n"
846 " set interface [PulseDial {enable|disable}]\n"
847 " set interface [Speaker {enable|disable}]"
848 }
849 };
850 #define N_MODEM_OPTIONS (sizeof(modemOptions) / sizeof(modemOptions[0]))
851
852
853 static Boolean
854 set_interface_modem(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
855 {
856 Boolean ok;
857
858 ok = _process_options(modemOptions, N_MODEM_OPTIONS, argc, argv, newConfiguration);
859 return ok;
860 }
861
862
863 /* -------------------- */
864
865
866 static int
867 __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
868 {
869 if (argc < 1) {
870 SCPrint(TRUE, stdout, CFSTR("PPP password not specified\n"));
871 return -1;
872 }
873
874 if (strlen(argv[0]) > 0) {
875 CFStringRef encryptionType;
876
877 encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption);
878 if (encryptionType == NULL) {
879 CFIndex n;
880 CFMutableDataRef pw;
881 CFStringRef str;
882
883 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
884 n = CFStringGetLength(str);
885 pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
886 CFDataSetLength(pw, n * sizeof(UniChar));
887 CFStringGetCharacters(str,
888 CFRangeMake(0, n),
889 (UniChar *)CFDataGetMutableBytePtr(pw));
890 CFRelease(str);
891
892 CFDictionarySetValue(newConfiguration, key, pw);
893 CFRelease(pw);
894 } else {
895 SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
896 return -1;
897 }
898 } else {
899 CFDictionaryRemoveValue(newConfiguration, key);
900 }
901
902 return 1;
903 }
904
905
906 static int
907 __doPPPAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
908 {
909 if (argc < 1) {
910 SCPrint(TRUE, stdout, CFSTR("PPP password type mode not specified\n"));
911 return -1;
912 }
913
914 if (strlen(argv[0]) > 0) {
915 if (strcasecmp(argv[0], "keychain") == 0) {
916 CFDictionarySetValue(newConfiguration, key, kSCValNetPPPAuthPasswordEncryptionKeychain);
917 } else {
918 SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
919 return -1;
920 }
921 } else {
922 CFDictionaryRemoveValue(newConfiguration, key);
923 }
924
925 // encryption type changed, reset password
926 CFDictionaryRemoveValue(newConfiguration, kSCPropNetPPPAuthPassword);
927
928 return 1;
929 }
930
931
932 static selections authPromptSelections[] = {
933 { CFSTR("before"), &kSCValNetPPPAuthPromptBefore, 0 },
934 { CFSTR("after") , &kSCValNetPPPAuthPromptAfter , 0 },
935 { NULL , NULL , 0 }
936 };
937
938
939 static selections authProtocolSelections[] = {
940 { CFSTR("CHAP") , &kSCValNetPPPAuthProtocolCHAP , 0 },
941 { CFSTR("EAP") , &kSCValNetPPPAuthProtocolEAP , 0 },
942 { CFSTR("MSCHAP1"), &kSCValNetPPPAuthProtocolMSCHAP1, 0 },
943 { CFSTR("MSCHAP2"), &kSCValNetPPPAuthProtocolMSCHAP2, 0 },
944 { CFSTR("PAP") , &kSCValNetPPPAuthProtocolPAP , 0 },
945 { NULL , NULL , 0 }
946 };
947
948
949 static options pppOptions[] = {
950 { "ACSP" , NULL , isBoolean , &kSCPropNetPPPACSPEnabled , NULL , NULL },
951 { "ConnectTime" , "?time" , isNumber , &kSCPropNetPPPConnectTime , NULL , NULL },
952 { "DialOnDemand" , NULL , isBoolean , &kSCPropNetPPPDialOnDemand , NULL , NULL },
953 { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetPPPDisconnectOnFastUserSwitch, NULL , NULL },
954 { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnIdle , NULL , NULL },
955 { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetPPPDisconnectOnIdleTimer , NULL , NULL },
956 { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnLogout , NULL , NULL },
957 { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnSleep , NULL , NULL },
958 { "DisconnectTime" , "?time" , isNumber , &kSCPropNetPPPDisconnectTime , NULL , NULL },
959 { "IdleReminder" , NULL , isBoolean , &kSCPropNetPPPIdleReminder , NULL , NULL },
960 { "IdleReminderTimer" , "time" , isNumber , &kSCPropNetPPPIdleReminderTimer , NULL , NULL },
961 { "Logfile" , "path" , isString , &kSCPropNetPPPLogfile , NULL , NULL },
962 { "Plugins" , "plugin" , isStringArray , &kSCPropNetPPPPlugins , NULL , NULL },
963 { "RetryConnectTime" , "time" , isNumber , &kSCPropNetPPPRetryConnectTime , NULL , NULL },
964 { "SessionTimer" , "time" , isNumber , &kSCPropNetPPPSessionTimer , NULL , NULL },
965 { "UseSessionTimer" , NULL , isBoolean , &kSCPropNetPPPUseSessionTimer , NULL , NULL },
966 { "VerboseLogging" , NULL , isBoolean , &kSCPropNetPPPVerboseLogging , NULL , NULL },
967
968 // --- Auth: ---
969 { "AuthEAPPlugins" , "plugin" , isStringArray , &kSCPropNetPPPAuthEAPPlugins , NULL , NULL },
970 { "AuthName" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL },
971 { "Account" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL },
972 { "AuthPassword" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL },
973 { "Password" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL },
974 { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetPPPAuthPasswordEncryption , __doPPPAuthPWType, NULL },
975 { "AuthPrompt" , "before/after", isChooseOne , &kSCPropNetPPPAuthPrompt , NULL , (void *)authPromptSelections },
976 { "AuthProtocol" , "protocol" , isChooseMultiple , &kSCPropNetPPPAuthProtocol , NULL , (void *)authProtocolSelections },
977
978 // --- Comm: ---
979 { "CommRemoteAddress" , "phone#" , isString , &kSCPropNetPPPCommRemoteAddress , NULL , NULL },
980 { "CommAlternateRemoteAddress", "phone#" , isString , &kSCPropNetPPPCommAlternateRemoteAddress, NULL , NULL },
981 { "CommConnectDelay" , "time" , isNumber , &kSCPropNetPPPCommConnectDelay , NULL , NULL },
982 { "CommDisplayTerminalWindow" , NULL , isBoolean , &kSCPropNetPPPCommDisplayTerminalWindow , NULL , NULL },
983 { "CommRedialCount" , "retry count" , isNumber , &kSCPropNetPPPCommRedialCount , NULL , NULL },
984 { "CommRedialEnabled" , NULL , isBoolean , &kSCPropNetPPPCommRedialEnabled , NULL , NULL },
985 { "CommRedialInterval" , "retry delay" , isNumber , &kSCPropNetPPPCommRedialInterval , NULL , NULL },
986 { "CommTerminalScript" , "script" , isString , &kSCPropNetPPPCommTerminalScript , NULL , NULL },
987 { "CommUseTerminalScript" , NULL , isBoolean , &kSCPropNetPPPCommUseTerminalScript , NULL , NULL },
988
989 // --- CCP: ---
990 { "CCPEnabled" , NULL , isBoolean , &kSCPropNetPPPCCPEnabled , NULL , NULL },
991 { "CCPMPPE40Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE40Enabled , NULL , NULL },
992 { "CCPMPPE128Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE128Enabled , NULL , NULL },
993
994 // --- IPCP: ---
995 { "IPCPCompressionVJ" , NULL , isBoolean , &kSCPropNetPPPIPCPCompressionVJ , NULL , NULL },
996 { "IPCPUsePeerDNS" , NULL , isBoolean , &kSCPropNetPPPIPCPUsePeerDNS , NULL , NULL },
997
998 // --- LCP: ---
999 { "LCPEchoEnabled" , NULL , isBoolean , &kSCPropNetPPPLCPEchoEnabled , NULL , NULL },
1000 { "LCPEchoFailure" , NULL , isNumber , &kSCPropNetPPPLCPEchoFailure , NULL , NULL },
1001 { "LCPEchoInterval" , NULL , isNumber , &kSCPropNetPPPLCPEchoInterval , NULL , NULL },
1002 { "LCPCompressionACField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionACField , NULL , NULL },
1003 { "LCPCompressionPField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionPField , NULL , NULL },
1004 { "LCPMRU" , NULL , isNumber , &kSCPropNetPPPLCPMRU , NULL , NULL },
1005 { "LCPMTU" , NULL , isNumber , &kSCPropNetPPPLCPMTU , NULL , NULL },
1006 { "LCPReceiveACCM" , NULL , isNumber , &kSCPropNetPPPLCPReceiveACCM , NULL , NULL },
1007 { "LCPTransmitACCM" , NULL , isNumber , &kSCPropNetPPPLCPTransmitACCM , NULL , NULL },
1008
1009 // --- Help ---
1010 { "?" , NULL , isHelp , NULL , NULL ,
1011 "\nPPP configuration commands\n\n"
1012 " set interface [Account account]\n"
1013 " set interface [Password password]\n"
1014 " set interface [Number telephone-number]\n"
1015 " set interface [AlternateNumber telephone-number]\n"
1016 " set interface [IdleReminder {enable|disable}]\n"
1017 " set interface [IdleReminderTimer time-in-seconds]\n"
1018 " set interface [DisconnectOnIdle {enable|disable}]\n"
1019 " set interface [DisconnectOnIdleTimer time-in-seconds]\n"
1020 " set interface [DisconnectOnLogout {enable|disable}]"
1021 }
1022 };
1023 #define N_PPP_OPTIONS (sizeof(pppOptions) / sizeof(pppOptions[0]))
1024
1025
1026 static Boolean
1027 set_interface_ppp(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1028 {
1029 Boolean ok;
1030
1031 ok = _process_options(pppOptions, N_PPP_OPTIONS, argc, argv, newConfiguration);
1032 return ok;
1033 }
1034
1035
1036 /* -------------------- */
1037
1038
1039 static Boolean
1040 set_interface_vlan(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1041 {
1042 // xxxxx ("device", "tag")
1043 SCPrint(TRUE, stdout, CFSTR("vlan interface management not yet supported\n"));
1044 return FALSE;
1045 }
1046
1047
1048 /* -------------------- */
1049
1050
1051 __private_extern__
1052 void
1053 set_interface(int argc, char **argv)
1054 {
1055 CFDictionaryRef configuration;
1056 CFStringRef interfaceType;
1057 CFMutableDictionaryRef newConfiguration = NULL;
1058 Boolean ok = FALSE;
1059
1060 if (net_interface == NULL) {
1061 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
1062 return;
1063 }
1064
1065 if (argc < 1) {
1066 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1067 return;
1068 }
1069
1070 configuration = SCNetworkInterfaceGetConfiguration(net_interface);
1071 if (configuration == NULL) {
1072 newConfiguration = CFDictionaryCreateMutable(NULL,
1073 0,
1074 &kCFTypeDictionaryKeyCallBacks,
1075 &kCFTypeDictionaryValueCallBacks);
1076 } else {
1077 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1078 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1079 }
1080
1081 interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
1082
1083 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
1084 ok = set_interface_bond(argc, argv, newConfiguration);
1085 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet)) {
1086 ok = set_interface_ethernet(argc, argv, newConfiguration);
1087 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeModem)) {
1088 ok = set_interface_modem(argc, argv, newConfiguration);
1089 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIEEE80211)) {
1090 ok = set_interface_airport(argc, argv, newConfiguration);
1091 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
1092 ok = set_interface_ppp(argc, argv, newConfiguration);
1093 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
1094 ok = set_interface_vlan(argc, argv, newConfiguration);
1095 } else {
1096 SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
1097 }
1098
1099 if (!ok) {
1100 goto done;
1101 }
1102
1103 if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
1104 ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
1105 if (!SCNetworkInterfaceSetConfiguration(net_interface, newConfiguration)) {
1106 if (SCError() == kSCStatusNoKey) {
1107 SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n"));
1108 } else {
1109 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1110 }
1111 goto done;
1112 }
1113
1114 net_changed = TRUE;
1115 }
1116
1117 done :
1118
1119 if (newConfiguration != NULL) CFRelease(newConfiguration);
1120 return;
1121 }
1122
1123
1124 /* -------------------- */
1125
1126
1127 __private_extern__
1128 void
1129 show_interface(int argc, char **argv)
1130 {
1131 SCNetworkInterfaceRef interface;
1132
1133 if (argc == 1) {
1134 interface = _find_interface(argv[0]);
1135 } else {
1136 if (net_interface != NULL) {
1137 interface = net_interface;
1138 } else {
1139 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
1140 return;
1141 }
1142 }
1143
1144 if (interface != NULL) {
1145 _show_interface(interface, CFSTR(""), TRUE);
1146 }
1147
1148 return;
1149 }
1150
1151
1152 /* -------------------- */
1153
1154
1155 __private_extern__
1156 CFStringRef
1157 _interface_description(SCNetworkInterfaceRef interface)
1158 {
1159 CFMutableStringRef description;
1160 CFStringRef if_bsd_name;
1161 CFStringRef if_type;
1162
1163 description = CFStringCreateMutable(NULL, 0);
1164
1165 if_type = SCNetworkInterfaceGetInterfaceType(interface);
1166 CFStringAppend(description, if_type);
1167
1168 if_bsd_name = SCNetworkInterfaceGetBSDName(interface);
1169 if (if_bsd_name != NULL) {
1170 CFStringAppendFormat(description, NULL, CFSTR(" (%@)"), if_bsd_name);
1171 }
1172
1173 interface = SCNetworkInterfaceGetInterface(interface);
1174 while ((interface != NULL) &&
1175 !CFEqual(interface, kSCNetworkInterfaceIPv4)) {
1176 CFStringRef childDescription;
1177
1178 childDescription = _interface_description(interface);
1179 CFStringAppendFormat(description, NULL, CFSTR(" / %@"), childDescription);
1180 CFRelease(childDescription);
1181
1182 interface = SCNetworkInterfaceGetInterface(interface);
1183 }
1184
1185 return description;
1186 }