X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/4c5e92e2493bdfbbce40e998f3b607c72c47af2c..dbf6a266c384fc8b55e00a396eebe5cb62e21547:/scutil.tproj/net_interface.c?ds=sidebyside diff --git a/scutil.tproj/net_interface.c b/scutil.tproj/net_interface.c new file mode 100644 index 0000000..a7bb46c --- /dev/null +++ b/scutil.tproj/net_interface.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Modification History + * + * August 5, 2004 Allan Nathanson + * - initial revision + */ + + +#include "scutil.h" +#include "net.h" + +#include + + +/* -------------------- */ + + +static CFArrayRef +_copy_interfaces() +{ + CFMutableArrayRef interfaces; + CFArrayRef real_interfaces; + + real_interfaces = SCNetworkInterfaceCopyAll(); + if (real_interfaces == NULL) { + SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); + return NULL; + } + + interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + // include real interfaces + CFArrayAppendArray(interfaces, + real_interfaces, + CFRangeMake(0, CFArrayGetCount(real_interfaces))); + CFRelease(real_interfaces); + + // include pseudo interfaces + CFArrayAppendValue(interfaces, kSCNetworkInterfaceIPv4); + + // include interfaces that we have created + if (new_interfaces != NULL) { + CFArrayAppendArray(interfaces, + new_interfaces, + CFRangeMake(0, CFArrayGetCount(new_interfaces))); + } + + return (CFArrayRef)interfaces; +} + + +__private_extern__ +SCNetworkInterfaceRef +_find_interface(char *match) +{ + Boolean allowIndex = TRUE; + CFIndex i; + CFIndex n; + CFStringRef select_name = NULL; + SCNetworkInterfaceRef selected = NULL; + + if (strcasecmp(match, "$child") == 0) { + if (net_interface == NULL) { + SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); + goto done; + } + + selected = SCNetworkInterfaceGetInterface(net_interface); + if(selected == NULL) { + SCPrint(TRUE, stdout, CFSTR("no child interface\n")); + } + + goto done; + } else if (strcasecmp(match, "$service") == 0) { + if (net_service == NULL) { + SCPrint(TRUE, stdout, CFSTR("service not selected\n")); + goto done; + } + + selected = SCNetworkServiceGetInterface(net_service); + if(selected == NULL) { + SCPrint(TRUE, stdout, CFSTR("no interface for service\n")); + } + + goto done; + } + + if (interfaces == NULL) { + interfaces = _copy_interfaces(); + if (interfaces == NULL) { + return NULL; + } + allowIndex = FALSE; + } + + // try to select the interface by its display name + + select_name = CFStringCreateWithCString(NULL, match, kCFStringEncodingUTF8); + + n = CFArrayGetCount(interfaces); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + CFStringRef interfaceName; + + interface = CFArrayGetValueAtIndex(interfaces, i); + interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface); + if ((interfaceName != NULL) && CFEqual(select_name, interfaceName)) { + if (selected == NULL) { + selected = interface; + } else { + // if multiple interfaces match + selected = NULL; + SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n")); + goto done; + } + } + } + + if (selected != NULL) { + goto done; + } + + // try to select the interface by its BSD name + + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + CFStringRef bsd_name = NULL; + + interface = CFArrayGetValueAtIndex(interfaces, i); + while ((interface != NULL) && (bsd_name == NULL)) { + bsd_name = SCNetworkInterfaceGetBSDName(interface); + if (bsd_name == NULL) { + interface = SCNetworkInterfaceGetInterface(interface); + } + } + + if ((bsd_name != NULL) && CFEqual(select_name, bsd_name)) { + if (selected == NULL) { + selected = interface; + } else { + // if multiple interfaces match + selected = NULL; + SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n")); + goto done; + } + } + } + + if (selected != NULL) { + goto done; + } + + // try to select the interface by its interface type + + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + CFStringRef interfaceType; + + interface = CFArrayGetValueAtIndex(interfaces, i); + interfaceType = SCNetworkInterfaceGetInterfaceType(interface); + if (CFEqual(select_name, interfaceType)) { + if (selected == NULL) { + selected = interface; + } else { + // if multiple interfaces match + selected = NULL; + SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n")); + goto done; + } + } + } + + if (selected != NULL) { + goto done; + } + + if (allowIndex) { + char *end; + char *str = match; + long val; + + // try to select the interface by its index + + errno = 0; + val = strtol(str, &end, 10); + if ((*str != '\0') && + ((*end == '\0') || (*end == '.')) && + (errno == 0)) { + if ((val > 0) && (val <= n)) { + selected = CFArrayGetValueAtIndex(interfaces, val - 1); + + if (*end == '.') { + str = end + 1; + val = strtol(str, &end, 10); + if ((*str != '\0') && (*end == '\0') && (errno == 0)) { + while (val-- > 0) { + selected = SCNetworkInterfaceGetInterface(selected); + if (selected == NULL) { + break; + } + } + } + } + } + } + } + + if (selected != NULL) { + goto done; + } + + SCPrint(TRUE, stdout, CFSTR("no match\n")); + + done : + + if (select_name != NULL) CFRelease(select_name); + return selected; +} + + +/* -------------------- */ + + +__private_extern__ +void +create_interface(int argc, char **argv) +{ + SCNetworkInterfaceRef interface; + CFStringRef interfaceName; + CFStringRef interfaceType; + SCNetworkInterfaceRef new_interface; + + if (argc < 1) { + SCPrint(TRUE, stdout, CFSTR("what interface type?\n")); + return; + } + + interfaceType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) { +// xxxxx +SCPrint(TRUE, stdout, CFSTR("vlan creation not yet supported\n")); +goto done; + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) { +// xxxxx +SCPrint(TRUE, stdout, CFSTR("bond creation not yet supported\n")); +goto done; + } else { + if (argc < 2) { + if (net_interface == NULL) { + SCPrint(TRUE, stdout, CFSTR("no network interface selected\n")); + goto done; + } + + interface = net_interface; + } else { + interface = _find_interface(argv[1]); + } + + if (interface == NULL) { + return; + } + + new_interface = SCNetworkInterfaceCreateWithInterface(interface, interfaceType); + if (new_interface == NULL) { + SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); + goto done; + } + } + + if (new_interfaces == NULL) { + new_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + CFArrayAppendValue(new_interfaces, new_interface); + + if (net_interface != NULL) CFRelease(net_interface); + net_interface = new_interface; + + interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(net_interface); + if (interfaceName == NULL) { + interfaceName = SCNetworkInterfaceGetBSDName(net_interface); + } + if (interfaceName == NULL) { + interfaceName = SCNetworkInterfaceGetInterfaceType(net_interface); + } + SCPrint(TRUE, stdout, CFSTR("interface \"%@\" created and selected\n"), interfaceName); + + done : + + CFRelease(interfaceType); + return; +} + + +/* -------------------- */ + + +__private_extern__ +void +select_interface(int argc, char **argv) +{ + SCNetworkInterfaceRef interface; + + interface = _find_interface(argv[0]); + + if (interface != NULL) { + CFStringRef interfaceName; + + if (net_interface != NULL) CFRelease(net_interface); + net_interface = CFRetain(interface); + + interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface); + if (interfaceName == NULL) { + interfaceName = SCNetworkInterfaceGetBSDName(interface); + } + if (interfaceName == NULL) { + interfaceName = SCNetworkInterfaceGetInterfaceType(interface); + } + + SCPrint(TRUE, stdout, CFSTR("interface \"%@\" selected\n"), interfaceName); + } + + return; +} + + +/* -------------------- */ + + +__private_extern__ +void +_show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean showChild) +{ + CFDictionaryRef configuration; + CFStringRef if_bsd_name; + CFStringRef if_localized_name; + CFStringRef if_mac_address; + CFStringRef if_type; + CFArrayRef supported; + + if_localized_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); + if (if_localized_name != NULL) { + SCPrint(TRUE, stdout, CFSTR("%@ name = %@\n"), prefix, if_localized_name); + } + + if_bsd_name = SCNetworkInterfaceGetBSDName(interface); + if (if_bsd_name != NULL) { + SCPrint(TRUE, stdout, CFSTR("%@ interface name = %@\n"), prefix, if_bsd_name); + } + + if_type = SCNetworkInterfaceGetInterfaceType(interface); + SCPrint(TRUE, stdout, CFSTR("%@ type = %@\n"), prefix, if_type); + + if_mac_address = SCNetworkInterfaceGetHardwareAddressString(interface); + if (if_mac_address != NULL) { + SCPrint(TRUE, stdout, CFSTR("%@ address = %@\n"), prefix, if_mac_address); + } + + configuration = SCNetworkInterfaceGetConfiguration(interface); + if ((configuration != NULL) && + CFDictionaryContainsKey(configuration, kSCResvInactive)) { + configuration = NULL; + } + + if (if_bsd_name != NULL) { + CFArrayRef available; + CFDictionaryRef active; + int mtu_cur; + int mtu_min; + int mtu_max; + + if (NetworkInterfaceCopyMTU(if_bsd_name, &mtu_cur, &mtu_min, &mtu_max)) { + char isCurrent = '*'; + + if (configuration != NULL) { + int mtu_req; + CFNumberRef num; + + num = CFDictionaryGetValue(configuration, kSCPropNetEthernetMTU); + if (isA_CFNumber(num)) { + CFNumberGetValue(num, kCFNumberIntType, &mtu_req); + if (mtu_cur != mtu_req) { + mtu_cur = mtu_req; + isCurrent = ' '; + } + } + } + + SCPrint(TRUE, stdout, CFSTR("%@ mtu %c = %ld (%ld < n < %ld)\n"), + prefix, + isCurrent, + mtu_cur, + mtu_min, + mtu_max); + } + + if (NetworkInterfaceCopyMediaOptions(if_bsd_name, NULL, &active, &available, TRUE)) { + char isCurrent = ' '; + CFArrayRef options = NULL; + CFArrayRef options_req = NULL; + CFStringRef subtype = NULL; + CFStringRef subtype_req = NULL; + + if (configuration != NULL) { + subtype_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaSubType); + options_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaOptions); + } + + if (subtype_req == NULL) { + subtype_req = CFSTR("autoselect"); + } + + if (active != NULL) { + subtype = CFDictionaryGetValue(active, kSCPropNetEthernetMediaSubType); + options = CFDictionaryGetValue(active, kSCPropNetEthernetMediaOptions); + } + + if (subtype != NULL) { + if (((subtype_req != NULL) && + CFEqual(subtype, subtype_req)) && + ((options == options_req) || + ((options != NULL) && + (options_req != NULL) && + CFEqual(options, options_req))) + ) { + isCurrent = '*'; + } else if ((subtype_req == NULL) || + ((subtype_req != NULL) && + CFEqual(subtype_req, CFSTR("autoselect")))) { + // if requested subtype not specified or "autoselect" + isCurrent = '*'; + } + } + + if (subtype_req != NULL) { + SCPrint(TRUE, stdout, CFSTR("%@ media %c = %@"), + prefix, + isCurrent, + subtype_req); + + if ((options_req != NULL) && + (CFArrayGetCount(options_req) > 0)) { + CFStringRef options_str; + + options_str = CFStringCreateByCombiningStrings(NULL, options_req, CFSTR(",")); + SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str); + CFRelease(options_str); + } + + SCPrint(TRUE, stdout, CFSTR("\n")); + } + + SCPrint(TRUE, stdout, CFSTR("\n")); + + if (available != NULL) { + CFIndex i; + CFIndex n_subtypes; + CFArrayRef subtypes; + + subtypes = NetworkInterfaceCopyMediaSubTypes(available); + n_subtypes = (subtypes != NULL) ? CFArrayGetCount(subtypes) : 0; + for (i = 0; i < n_subtypes; i++) { + CFIndex j; + CFIndex n_subtype_options; + CFStringRef subtype; + CFArrayRef subtype_options; + + subtype = CFArrayGetValueAtIndex(subtypes, i); + subtype_options = NetworkInterfaceCopyMediaSubTypeOptions(available, subtype); + n_subtype_options = (subtype_options != NULL) ? CFArrayGetCount(subtype_options) : 0; + for (j = 0; j < n_subtype_options; j++) { + char isCurrent = ' '; + CFArrayRef options; + + options = CFArrayGetValueAtIndex(subtype_options, j); + + if (((subtype_req != NULL) && + CFEqual(subtype, subtype_req)) && + ((options == options_req) || + ((options != NULL) && + (options_req != NULL) && + CFEqual(options, options_req))) + ) { + isCurrent = '*'; + } + + SCPrint(TRUE, stdout, CFSTR("%@ %s %c = %@"), + prefix, + ((i == 0) && (j == 0)) ? "supported media" : " ", + isCurrent, + subtype); + + if ((options != NULL) && + (CFArrayGetCount(options) > 0)) { + CFStringRef options_str; + + options_str = CFStringCreateByCombiningStrings(NULL, options, CFSTR(",")); + SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str); + CFRelease(options_str); + } + + SCPrint(TRUE, stdout, CFSTR("\n")); + } + CFRelease(subtype_options); + } + } + } else { + SCPrint(TRUE, stdout, CFSTR("\n")); + } + } + + supported = SCNetworkInterfaceGetSupportedInterfaceTypes(interface); + SCPrint(TRUE, stdout, CFSTR("%@ supported interfaces = "), prefix); + if (supported != NULL) { + CFIndex i; + CFIndex n = CFArrayGetCount(supported); + + for (i = 0; i < n; i++) { + SCPrint(TRUE, stdout, CFSTR("%s%@"), + (i == 0) ? "" : ", ", + CFArrayGetValueAtIndex(supported, i)); + } + } + SCPrint(TRUE, stdout, CFSTR("\n")); + + supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface); + SCPrint(TRUE, stdout, CFSTR("%@ supported protocols = "), prefix); + if (supported != NULL) { + CFIndex i; + CFIndex n = CFArrayGetCount(supported); + + for (i = 0; i < n; i++) { + SCPrint(TRUE, stdout, CFSTR("%s%@"), + (i == 0) ? "" : ", ", + CFArrayGetValueAtIndex(supported, i)); + } + } + SCPrint(TRUE, stdout, CFSTR("\n")); + + if (configuration != NULL) { + CFMutableDictionaryRef effective; + + effective = CFDictionaryCreateMutableCopy(NULL, 0, configuration); + + // remove known (and already reported) interface configuration keys + if (CFDictionaryContainsKey(effective, kSCResvInactive)) { + CFDictionaryRemoveAllValues(effective); + } + CFDictionaryRemoveValue(effective, kSCPropNetEthernetMTU); + CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaSubType); + CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaOptions); + + if (CFDictionaryGetCount(effective) > 0) { + SCPrint(TRUE, stdout, CFSTR("\n%@ per-interface configuration\n"), prefix); + _show_entity(configuration, prefix); + } + + CFRelease(effective); + } + + if (_sc_debug) { + SCPrint(TRUE, stdout, CFSTR("\n%@\n"), interface); + } + + interface = SCNetworkInterfaceGetInterface(interface); + if (interface != NULL) { + CFStringRef newPrefix; + + newPrefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ "), prefix); + SCPrint(TRUE, stdout, CFSTR("\n%@child interface\n"), newPrefix); + _show_interface(interface, newPrefix, showChild); + CFRelease(newPrefix); + } + + return; +} + + +/* -------------------- */ + + +__private_extern__ +void +show_interfaces(int argc, char **argv) +{ + CFIndex i; + CFIndex n; + + if (interfaces != NULL) CFRelease(interfaces); + interfaces = _copy_interfaces(); + if (interfaces == NULL) { + return; + } + + n = CFArrayGetCount(interfaces); + for (i = 0; i < n; i++) { + CFIndex childIndex = 0; + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(interfaces, i); + do { + CFStringRef interfaceName; + char isSelected; + + interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface); + if (interfaceName == NULL) { + interfaceName = SCNetworkInterfaceGetBSDName(interface); + } + if (interfaceName == NULL) { + interfaceName = SCNetworkInterfaceGetInterfaceType(interface); + } + + isSelected = ' '; + if ((net_interface != NULL) && CFEqual(interface, net_interface)) { + isSelected = '>'; + } + + if (childIndex == 0) { + SCPrint(TRUE, stdout, CFSTR("%c%2d: %@\n"), + isSelected, + i + 1, + interfaceName); + } else { + SCPrint(TRUE, stdout, CFSTR("%c%2d.%d: %@\n"), + isSelected, + i + 1, + childIndex, + interfaceName); + } + + interface = SCNetworkInterfaceGetInterface(interface); + childIndex++; + } while (interface != NULL); + } + + return; +} + + +/* -------------------- */ + + +static Boolean +set_interface_bond(int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ +// xxxxx ("+device", "-device") +SCPrint(TRUE, stdout, CFSTR("bond interface management not yet supported\n")); + return FALSE; +} + + +/* -------------------- */ + + +static Boolean +set_interface_airport(int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ +SCPrint(TRUE, stdout, CFSTR("airport interface management not yet supported\n")); + return FALSE; +} + + +/* -------------------- */ + + +static options ethernetOptions[] = { + { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL }, + { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL }, + { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL }, + + { "?" , NULL , isHelp , NULL , NULL, + "\nEthernet configuration commands\n\n" + " set interface [mtu n] [media type] [mediaopts opts]\n" + } +}; +#define N_ETHERNET_OPTIONS (sizeof(ethernetOptions) / sizeof(ethernetOptions[0])) + + +static Boolean +set_interface_ethernet(int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ + CFStringRef interfaceName; + Boolean ok; + + interfaceName = SCNetworkInterfaceGetBSDName(net_interface); + if (interfaceName == NULL) { + SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); + return FALSE; + } + + ok = _process_options(ethernetOptions, N_ETHERNET_OPTIONS, argc, argv, newConfiguration); + if (ok) { + CFNumberRef mtu; + CFArrayRef options; + CFStringRef subtype; + + // validate configuration + + mtu = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMTU); + if (isA_CFNumber(mtu)) { + int mtu_max; + int mtu_min; + int mtu_val; + + if (!NetworkInterfaceCopyMTU(interfaceName, NULL, &mtu_min, &mtu_max)) { + SCPrint(TRUE, stdout, CFSTR("cannot set MTU\n")); + return FALSE; + } + + if (!CFNumberGetValue(mtu, kCFNumberIntType, &mtu_val) || + (mtu_val < mtu_min) || + (mtu_val > mtu_max)) { + SCPrint(TRUE, stdout, CFSTR("mtu out of range\n")); + return FALSE; + } + } + + subtype = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaSubType); + options = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaOptions); + + if (subtype != NULL) { + CFArrayRef available = NULL; + CFArrayRef config_options = options; + CFArrayRef subtypes = NULL; + CFArrayRef subtype_options = NULL; + + ok = FALSE; + + if (options == NULL) { + config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); + } + + if (interfaceName == NULL) { + SCPrint(TRUE, stdout, CFSTR("media type / options not available\n")); + goto checked; + } + + if (!NetworkInterfaceCopyMediaOptions(interfaceName, NULL, NULL, &available, FALSE)) { + SCPrint(TRUE, stdout, CFSTR("media type / options not available\n")); + goto checked; + } + + if (available == NULL) { + goto checked; + } + + subtypes = NetworkInterfaceCopyMediaSubTypes(available); + if ((subtypes == NULL) || + !CFArrayContainsValue(subtypes, + CFRangeMake(0, CFArrayGetCount(subtypes)), + subtype)) { + SCPrint(TRUE, stdout, CFSTR("media type not valid\n")); + goto checked; + } + + subtype_options = NetworkInterfaceCopyMediaSubTypeOptions(available, subtype); + if ((subtype_options == NULL) || + !CFArrayContainsValue(subtype_options, + CFRangeMake(0, CFArrayGetCount(subtype_options)), + config_options)) { + SCPrint(TRUE, stdout, CFSTR("media options not valid for \"%@\"\n"), subtype); + goto checked; + } + + if (options == NULL) { + CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaOptions, config_options); + } + + ok = TRUE; + + checked : + + if (available != NULL) CFRelease(available); + if (subtypes != NULL) CFRelease(subtypes); + if (subtype_options != NULL) CFRelease(subtype_options); + if (options == NULL) CFRelease(config_options); + } else { + if (options != NULL) { + SCPrint(TRUE, stdout, CFSTR("media type and options must both be specified\n")); + return FALSE; + } + } + } + + return ok; +} + + +/* -------------------- */ + + +static selections modemDialSelections[] = { + { CFSTR("ignore"), &kSCValNetModemDialModeIgnoreDialTone , 0 }, + { CFSTR("manual"), &kSCValNetModemDialModeManual , 0 }, + { CFSTR("wait") , &kSCValNetModemDialModeWaitForDialTone, 0 }, + { NULL , NULL , 0 } +}; + +static options modemOptions[] = { + { "ConnectionScript" , "script", isString , &kSCPropNetModemConnectionScript , NULL, NULL }, + { "DialMode" , "mode" , isChooseOne, &kSCPropNetModemDialMode , NULL, (void *)modemDialSelections }, + { "CallWaiting" , NULL , isBoolean , &kSCPropNetModemHoldEnabled , NULL, NULL }, + { "CallWaitingAlert" , NULL , isBoolean , &kSCPropNetModemHoldCallWaitingAudibleAlert, NULL, NULL }, + { "CallWaitingDisconnectOnAnswer", NULL , isBoolean , &kSCPropNetModemHoldDisconnectOnAnswer , NULL, NULL }, + { "DataCompression" , NULL , isBoolean , &kSCPropNetModemDataCompression , NULL, NULL }, + { "ErrorCorrection" , NULL , isBoolean , &kSCPropNetModemErrorCorrection , NULL, NULL }, + { "HoldReminder" , NULL , isBoolean , &kSCPropNetModemHoldReminder , NULL, NULL }, + { "HoldReminderTime" , "time" , isNumber , &kSCPropNetModemHoldReminderTime , NULL, NULL }, + { "PulseDial" , NULL , isBoolean , &kSCPropNetModemPulseDial , NULL, NULL }, + { "Speaker" , NULL , isBoolean , &kSCPropNetModemSpeaker , NULL, NULL }, + + { "?" , NULL , isHelp , NULL , NULL, + "\nModem configuration commands\n\n" + " set interface [ConnectionScript connection-script]\n" + " set interface [CallWaiting {enable|disable}]\n" + " set interface [CallWaitingAlert {enable|disable}]\n" + " set interface [CallWaitingDisconnectOnAnswer {enable|disable}]\n" + " set interface [DialMode {ignore|wait}]\n" + " set interface [DataCompression {enable|disable}]\n" + " set interface [ErrorCorrection {enable|disable}]\n" + " set interface [HoldReminder {enable|disable}]\n" + " set interface [HoldReminderTime n]\n" + " set interface [PulseDial {enable|disable}]\n" + " set interface [Speaker {enable|disable}]" + } +}; +#define N_MODEM_OPTIONS (sizeof(modemOptions) / sizeof(modemOptions[0])) + + +static Boolean +set_interface_modem(int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ + Boolean ok; + + ok = _process_options(modemOptions, N_MODEM_OPTIONS, argc, argv, newConfiguration); + return ok; +} + + +/* -------------------- */ + + +static int +__doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ + if (argc < 1) { + SCPrint(TRUE, stdout, CFSTR("PPP password not specified\n")); + return -1; + } + + if (strlen(argv[0]) > 0) { + CFStringRef encryptionType; + + encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption); + if (encryptionType == NULL) { + CFIndex n; + CFMutableDataRef pw; + CFStringRef str; + + str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + n = CFStringGetLength(str); + pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); + CFDataSetLength(pw, n * sizeof(UniChar)); + CFStringGetCharacters(str, + CFRangeMake(0, n), + (UniChar *)CFDataGetMutableBytePtr(pw)); + CFRelease(str); + + CFDictionarySetValue(newConfiguration, key, pw); + CFRelease(pw); + } else { + SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType); + return -1; + } + } else { + CFDictionaryRemoveValue(newConfiguration, key); + } + + return 1; +} + + +static int +__doPPPAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ + if (argc < 1) { + SCPrint(TRUE, stdout, CFSTR("PPP password type mode not specified\n")); + return -1; + } + + if (strlen(argv[0]) > 0) { + if (strcasecmp(argv[0], "keychain") == 0) { + CFDictionarySetValue(newConfiguration, key, kSCValNetPPPAuthPasswordEncryptionKeychain); + } else { + SCPrint(TRUE, stdout, CFSTR("invalid password type\n")); + return -1; + } + } else { + CFDictionaryRemoveValue(newConfiguration, key); + } + + // encryption type changed, reset password + CFDictionaryRemoveValue(newConfiguration, kSCPropNetPPPAuthPassword); + + return 1; +} + + +static selections authPromptSelections[] = { + { CFSTR("before"), &kSCValNetPPPAuthPromptBefore, 0 }, + { CFSTR("after") , &kSCValNetPPPAuthPromptAfter , 0 }, + { NULL , NULL , 0 } +}; + + +static selections authProtocolSelections[] = { + { CFSTR("CHAP") , &kSCValNetPPPAuthProtocolCHAP , 0 }, + { CFSTR("EAP") , &kSCValNetPPPAuthProtocolEAP , 0 }, + { CFSTR("MSCHAP1"), &kSCValNetPPPAuthProtocolMSCHAP1, 0 }, + { CFSTR("MSCHAP2"), &kSCValNetPPPAuthProtocolMSCHAP2, 0 }, + { CFSTR("PAP") , &kSCValNetPPPAuthProtocolPAP , 0 }, + { NULL , NULL , 0 } +}; + + +static options pppOptions[] = { + { "ACSP" , NULL , isBoolean , &kSCPropNetPPPACSPEnabled , NULL , NULL }, + { "ConnectTime" , "?time" , isNumber , &kSCPropNetPPPConnectTime , NULL , NULL }, + { "DialOnDemand" , NULL , isBoolean , &kSCPropNetPPPDialOnDemand , NULL , NULL }, + { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetPPPDisconnectOnFastUserSwitch, NULL , NULL }, + { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnIdle , NULL , NULL }, + { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetPPPDisconnectOnIdleTimer , NULL , NULL }, + { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnLogout , NULL , NULL }, + { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnSleep , NULL , NULL }, + { "DisconnectTime" , "?time" , isNumber , &kSCPropNetPPPDisconnectTime , NULL , NULL }, + { "IdleReminder" , NULL , isBoolean , &kSCPropNetPPPIdleReminder , NULL , NULL }, + { "IdleReminderTimer" , "time" , isNumber , &kSCPropNetPPPIdleReminderTimer , NULL , NULL }, + { "Logfile" , "path" , isString , &kSCPropNetPPPLogfile , NULL , NULL }, + { "Plugins" , "plugin" , isStringArray , &kSCPropNetPPPPlugins , NULL , NULL }, + { "RetryConnectTime" , "time" , isNumber , &kSCPropNetPPPRetryConnectTime , NULL , NULL }, + { "SessionTimer" , "time" , isNumber , &kSCPropNetPPPSessionTimer , NULL , NULL }, + { "UseSessionTimer" , NULL , isBoolean , &kSCPropNetPPPUseSessionTimer , NULL , NULL }, + { "VerboseLogging" , NULL , isBoolean , &kSCPropNetPPPVerboseLogging , NULL , NULL }, + + // --- Auth: --- + { "AuthEAPPlugins" , "plugin" , isStringArray , &kSCPropNetPPPAuthEAPPlugins , NULL , NULL }, + { "AuthName" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL }, + { "Account" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL }, + { "AuthPassword" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL }, + { "Password" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL }, + { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetPPPAuthPasswordEncryption , __doPPPAuthPWType, NULL }, + { "AuthPrompt" , "before/after", isChooseOne , &kSCPropNetPPPAuthPrompt , NULL , (void *)authPromptSelections }, + { "AuthProtocol" , "protocol" , isChooseMultiple , &kSCPropNetPPPAuthProtocol , NULL , (void *)authProtocolSelections }, + + // --- Comm: --- + { "CommRemoteAddress" , "phone#" , isString , &kSCPropNetPPPCommRemoteAddress , NULL , NULL }, + { "CommAlternateRemoteAddress", "phone#" , isString , &kSCPropNetPPPCommAlternateRemoteAddress, NULL , NULL }, + { "CommConnectDelay" , "time" , isNumber , &kSCPropNetPPPCommConnectDelay , NULL , NULL }, + { "CommDisplayTerminalWindow" , NULL , isBoolean , &kSCPropNetPPPCommDisplayTerminalWindow , NULL , NULL }, + { "CommRedialCount" , "retry count" , isNumber , &kSCPropNetPPPCommRedialCount , NULL , NULL }, + { "CommRedialEnabled" , NULL , isBoolean , &kSCPropNetPPPCommRedialEnabled , NULL , NULL }, + { "CommRedialInterval" , "retry delay" , isNumber , &kSCPropNetPPPCommRedialInterval , NULL , NULL }, + { "CommTerminalScript" , "script" , isString , &kSCPropNetPPPCommTerminalScript , NULL , NULL }, + { "CommUseTerminalScript" , NULL , isBoolean , &kSCPropNetPPPCommUseTerminalScript , NULL , NULL }, + + // --- CCP: --- + { "CCPEnabled" , NULL , isBoolean , &kSCPropNetPPPCCPEnabled , NULL , NULL }, + { "CCPMPPE40Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE40Enabled , NULL , NULL }, + { "CCPMPPE128Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE128Enabled , NULL , NULL }, + + // --- IPCP: --- + { "IPCPCompressionVJ" , NULL , isBoolean , &kSCPropNetPPPIPCPCompressionVJ , NULL , NULL }, + { "IPCPUsePeerDNS" , NULL , isBoolean , &kSCPropNetPPPIPCPUsePeerDNS , NULL , NULL }, + + // --- LCP: --- + { "LCPEchoEnabled" , NULL , isBoolean , &kSCPropNetPPPLCPEchoEnabled , NULL , NULL }, + { "LCPEchoFailure" , NULL , isNumber , &kSCPropNetPPPLCPEchoFailure , NULL , NULL }, + { "LCPEchoInterval" , NULL , isNumber , &kSCPropNetPPPLCPEchoInterval , NULL , NULL }, + { "LCPCompressionACField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionACField , NULL , NULL }, + { "LCPCompressionPField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionPField , NULL , NULL }, + { "LCPMRU" , NULL , isNumber , &kSCPropNetPPPLCPMRU , NULL , NULL }, + { "LCPMTU" , NULL , isNumber , &kSCPropNetPPPLCPMTU , NULL , NULL }, + { "LCPReceiveACCM" , NULL , isNumber , &kSCPropNetPPPLCPReceiveACCM , NULL , NULL }, + { "LCPTransmitACCM" , NULL , isNumber , &kSCPropNetPPPLCPTransmitACCM , NULL , NULL }, + + // --- Help --- + { "?" , NULL , isHelp , NULL , NULL , + "\nPPP configuration commands\n\n" + " set interface [Account account]\n" + " set interface [Password password]\n" + " set interface [Number telephone-number]\n" + " set interface [AlternateNumber telephone-number]\n" + " set interface [IdleReminder {enable|disable}]\n" + " set interface [IdleReminderTimer time-in-seconds]\n" + " set interface [DisconnectOnIdle {enable|disable}]\n" + " set interface [DisconnectOnIdleTimer time-in-seconds]\n" + " set interface [DisconnectOnLogout {enable|disable}]" + } +}; +#define N_PPP_OPTIONS (sizeof(pppOptions) / sizeof(pppOptions[0])) + + +static Boolean +set_interface_ppp(int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ + Boolean ok; + + ok = _process_options(pppOptions, N_PPP_OPTIONS, argc, argv, newConfiguration); + return ok; +} + + +/* -------------------- */ + + +static Boolean +set_interface_vlan(int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ +// xxxxx ("device", "tag") +SCPrint(TRUE, stdout, CFSTR("vlan interface management not yet supported\n")); + return FALSE; +} + + +/* -------------------- */ + + +__private_extern__ +void +set_interface(int argc, char **argv) +{ + CFDictionaryRef configuration; + CFStringRef interfaceType; + CFMutableDictionaryRef newConfiguration = NULL; + Boolean ok = FALSE; + + if (net_interface == NULL) { + SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); + return; + } + + if (argc < 1) { + SCPrint(TRUE, stdout, CFSTR("set what?\n")); + return; + } + + configuration = SCNetworkInterfaceGetConfiguration(net_interface); + if (configuration == NULL) { + newConfiguration = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } else { + newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); + CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); + } + + interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface); + + if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) { + ok = set_interface_bond(argc, argv, newConfiguration); + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet)) { + ok = set_interface_ethernet(argc, argv, newConfiguration); + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeModem)) { + ok = set_interface_modem(argc, argv, newConfiguration); + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIEEE80211)) { + ok = set_interface_airport(argc, argv, newConfiguration); + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { + ok = set_interface_ppp(argc, argv, newConfiguration); + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) { + ok = set_interface_vlan(argc, argv, newConfiguration); + } else { + SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n")); + } + + if (!ok) { + goto done; + } + + if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) || + ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) { + if (!SCNetworkInterfaceSetConfiguration(net_interface, newConfiguration)) { + if (SCError() == kSCStatusNoKey) { + SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n")); + } else { + SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); + } + goto done; + } + + net_changed = TRUE; + } + + done : + + if (newConfiguration != NULL) CFRelease(newConfiguration); + return; +} + + +/* -------------------- */ + + +__private_extern__ +void +show_interface(int argc, char **argv) +{ + SCNetworkInterfaceRef interface; + + if (argc == 1) { + interface = _find_interface(argv[0]); + } else { + if (net_interface != NULL) { + interface = net_interface; + } else { + SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); + return; + } + } + + if (interface != NULL) { + _show_interface(interface, CFSTR(""), TRUE); + } + + return; +} + + +/* -------------------- */ + + +__private_extern__ +CFStringRef +_interface_description(SCNetworkInterfaceRef interface) +{ + CFMutableStringRef description; + CFStringRef if_bsd_name; + CFStringRef if_type; + + description = CFStringCreateMutable(NULL, 0); + + if_type = SCNetworkInterfaceGetInterfaceType(interface); + CFStringAppend(description, if_type); + + if_bsd_name = SCNetworkInterfaceGetBSDName(interface); + if (if_bsd_name != NULL) { + CFStringAppendFormat(description, NULL, CFSTR(" (%@)"), if_bsd_name); + } + + interface = SCNetworkInterfaceGetInterface(interface); + while ((interface != NULL) && + !CFEqual(interface, kSCNetworkInterfaceIPv4)) { + CFStringRef childDescription; + + childDescription = _interface_description(interface); + CFStringAppendFormat(description, NULL, CFSTR(" / %@"), childDescription); + CFRelease(childDescription); + + interface = SCNetworkInterfaceGetInterface(interface); + } + + return description; +}