]> git.saurik.com Git - apple/configd.git/blobdiff - scutil.tproj/net_interface.c
configd-453.16.tar.gz
[apple/configd.git] / scutil.tproj / net_interface.c
index 9cd9f3885e03a77104a0783c310f613dfc26b469..ba122042e16a110e3da0505014fae73e9c1458cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -29,6 +29,7 @@
  */
 
 
+#include <TargetConditionals.h>
 #include "scutil.h"
 #include "net.h"
 #include "prefs.h"
 #include <SystemConfiguration/LinkConfiguration.h>
 
 
+#if    TARGET_OS_EMBEDDED
+#define        INLINE_PASSWORDS_USE_CFSTRING
+#endif // TARGET_OS_EMBEDDED
+
+
 #pragma mark -
 #pragma mark Interface management
 
@@ -46,7 +52,7 @@ _copy_interfaces()
        CFMutableArrayRef       interfaces;
        CFArrayRef              real_interfaces;
 
-       real_interfaces = SCNetworkInterfaceCopyAll();
+       real_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs);
        if (real_interfaces == NULL) {
                SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
                return NULL;
@@ -61,6 +67,7 @@ _copy_interfaces()
        CFRelease(real_interfaces);
 
        // include pseudo interfaces
+       CFArrayAppendValue(interfaces, kSCNetworkInterfaceLoopback);
        CFArrayAppendValue(interfaces, kSCNetworkInterfaceIPv4);
 
        // include interfaces that we have created
@@ -116,8 +123,10 @@ _find_interface(int argc, char **argv, int *nArgs)
                }
 
                goto done;
+       }
+
 #if    !TARGET_OS_IPHONE
-       else if (strcasecmp(argv[0], "$bond") == 0) {
+       else if (strcasecmp(argv[0], "$bond") == 0) {
                CFStringRef     interfaceType;
 
                if (net_interface == NULL) {
@@ -145,7 +154,40 @@ _find_interface(int argc, char **argv, int *nArgs)
                        goto done;
                }
                allowIndex = FALSE;
-       } else if (strcasecmp(argv[0], "$vlan") == 0) {
+       }
+#endif // !TARGET_OS_IPHONE
+
+       else if (strcasecmp(argv[0], "$bridge") == 0) {
+               CFStringRef     interfaceType;
+
+               if (net_interface == NULL) {
+                       SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
+                       goto done;
+               }
+
+               interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
+               if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
+                       SCPrint(TRUE, stdout, CFSTR("interface not Bridge\n"));
+                       goto done;
+               }
+
+               if (argc < 2) {
+                       SCPrint(TRUE, stdout, CFSTR("no member interface specified\n"));
+                       return NULL;
+               }
+               argv++;
+               argc--;
+               if (nArgs != NULL) *nArgs += 1;
+
+               myInterfaces = SCBridgeInterfaceGetMemberInterfaces(net_interface);
+               if (myInterfaces == NULL) {
+                       SCPrint(TRUE, stdout, CFSTR("no member interfaces\n"));
+                       goto done;
+               }
+               allowIndex = FALSE;
+       }
+
+       else if (strcasecmp(argv[0], "$vlan") == 0) {
                CFStringRef     interfaceType;
 
                if (net_interface == NULL) {
@@ -165,7 +207,6 @@ _find_interface(int argc, char **argv, int *nArgs)
                }
 
                goto done;
-#endif // !TARGET_OS_IPHONE
        }
 
        if ((myInterfaces == NULL) && (interfaces == NULL)) {
@@ -323,16 +364,18 @@ create_interface(int argc, char **argv)
        argv++;
        argc--;
 
-#if    !TARGET_OS_IPHONE
        if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
                SCPrint(TRUE, stdout, CFSTR("bond creation not yet supported\n"));
                goto done;
        }
+       if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
+               SCPrint(TRUE, stdout, CFSTR("bridge creation not yet supported\n"));
+               goto done;
+       }
        if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
                SCPrint(TRUE, stdout, CFSTR("vlan creation not yet supported\n"));
                goto done;
        }
-#endif // !TARGET_OS_IPHONE
 
        if (argc < 1) {
                if (net_interface == NULL) {
@@ -451,10 +494,56 @@ _show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean sho
        if (if_bsd_name != NULL) {
                CFArrayRef      available;
                CFDictionaryRef active;
+               CFDictionaryRef cap_current;
                int             mtu_cur;
                int             mtu_min;
                int             mtu_max;
 
+               cap_current = SCNetworkInterfaceCopyCapability(interface, NULL);
+               if (cap_current != NULL) {
+                       CFIndex                 i;
+                       CFArrayRef              cap_names;
+                       CFMutableArrayRef       cap_sorted;
+                       const void              **keys;
+                       CFIndex                 n;
+
+                       n = CFDictionaryGetCount(cap_current);
+                       keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
+                       CFDictionaryGetKeysAndValues(cap_current, keys, NULL);
+                       cap_names = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
+                       CFAllocatorDeallocate(NULL, keys);
+
+                       cap_sorted = CFArrayCreateMutableCopy(NULL, 0, cap_names);
+                       CFRelease(cap_names);
+
+                       CFArraySortValues(cap_sorted, CFRangeMake(0, n), (CFComparatorFunction)CFStringCompare, NULL);
+
+                       SCPrint(TRUE, stdout, CFSTR("%@  capabilities         = "), prefix);
+                       for (i = 0; i < n; i++) {
+                               CFStringRef     cap_name;
+                               int             cap_val;
+                               CFNumberRef     val     = NULL;
+
+                               cap_name = CFArrayGetValueAtIndex(cap_sorted, i);
+                               if (configuration != NULL) {
+                                       val = CFDictionaryGetValue(configuration, cap_name);
+                               }
+                               if (!isA_CFNumber(val)) {
+                                       val = CFDictionaryGetValue(cap_current, cap_name);
+                               }
+
+                               SCPrint(TRUE, stdout, CFSTR("%s%@%c"),
+                                       (i == 0) ? "" : ",",
+                                       cap_name,
+                                       (CFNumberGetValue(val, kCFNumberIntType, &cap_val) &&
+                                        (cap_val != 0)) ? '+' : '-');
+                       }
+                       SCPrint(TRUE, stdout, CFSTR("\n"));
+
+                       CFRelease(cap_sorted);
+                       CFRelease(cap_current);
+               }
+
                if (SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
                        char    isCurrent       = '*';
 
@@ -587,7 +676,7 @@ _show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean sho
 
                                                SCPrint(TRUE, stdout, CFSTR("\n"));
                                        }
-                                       CFRelease(subtype_options);
+                                       if (subtype_options != NULL) CFRelease(subtype_options);
                                }
                                if (subtypes != NULL) CFRelease(subtypes);
                        }
@@ -840,21 +929,104 @@ show_interfaces(int argc, char **argv)
 }
 
 
-#pragma mark -
-#pragma mark Bond options
+/* -------------------- */
 
 
-#if    !TARGET_OS_IPHONE
+static int
+__doRank(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+       SCNetworkInterfaceRef           interface;
+       CFStringRef                     interfaceName;
+       Boolean                         ok      = FALSE;
+       SCNetworkServicePrimaryRank     rank    = kSCNetworkServicePrimaryRankDefault;
+       SCDynamicStoreRef               store;
+
+       if (argc < 1) {
+               SCPrint(TRUE, stdout,
+                       CFSTR("%s not specified\n"),
+                       description != NULL ? description : "rank");
+               return -1;
+       }
+
+       if (strlen(argv[0]) == 0) {
+               rank = kSCNetworkServicePrimaryRankDefault;
+       } else if ((strcasecmp(argv[0], "First") == 0)) {
+               rank = kSCNetworkServicePrimaryRankFirst;
+       } else if ((strcasecmp(argv[0], "Last") == 0)) {
+               rank = kSCNetworkServicePrimaryRankLast;
+       } else if ((strcasecmp(argv[0], "Never") == 0)) {
+               rank = kSCNetworkServicePrimaryRankNever;
+       } else {
+               SCPrint(TRUE, stdout, CFSTR("invalid rank\n"));
+               return -1;
+       }
+
+       interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
+       if (interfaceName == NULL) {
+               SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
+               return FALSE;
+       }
+
+       store = SCDynamicStoreCreate(NULL, CFSTR("scutil --net"), NULL, NULL);
+       interface = _SCNetworkInterfaceCopyActive(store, interfaceName);
+       CFRelease(store);
+       if (interface == NULL) {
+               SCPrint(TRUE, stdout, CFSTR("No active interface\n"));
+               return -1;
+       }
+
+       ok = SCNetworkInterfaceSetPrimaryRank(interface, rank);
+       CFRelease(interface);
+       if (!ok) {
+               SCPrint(TRUE, stdout, CFSTR("could not update per-interface rank\n"));
+               return -1;
+       }
+
+       return 1;
+}
+
+
+/* -------------------- */
+
+
+static void
+_replaceOne(const void *key, const void *value, void *context)
+{
+       CFMutableDictionaryRef  newConfiguration        = (CFMutableDictionaryRef)context;
+
+       CFDictionarySetValue(newConfiguration, key, value);
+       return;
+}
+
+
+static void
+updateInterfaceConfiguration(CFMutableDictionaryRef newConfiguration)
+{
+       CFDictionaryRef configuration;
+
+       CFDictionaryRemoveAllValues(newConfiguration);
+
+       configuration = SCNetworkInterfaceGetConfiguration(net_interface);
+       if (configuration != NULL) {
+               CFDictionaryApplyFunction(configuration, _replaceOne, (void *)newConfiguration);
+       }
+
+       return;
+}
+
+
+#pragma mark -
+#pragma mark Bond options
 
 
 static options bondOptions[] = {
        { "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
-// xxx  { "+device"   , ... },
-// xxx  { "-device"   , ... },
+       // xxx  { "+device"   , ... },
+       // xxx  { "-device"   , ... },
 
        { "?"         , NULL , isHelp     , NULL                            , NULL,
-           "\nBond configuration commands\n\n"
-           " set interface [mtu n] [media type] [mediaopts opts]\n"
+               "\nBond configuration commands\n\n"
+               " set interface [mtu n] [media type] [mediaopts opts]\n"
        }
 };
 #define        N_BOND_OPTIONS  (sizeof(bondOptions) / sizeof(bondOptions[0]))
@@ -884,7 +1056,45 @@ set_interface_bond(int argc, char **argv, CFMutableDictionaryRef newConfiguratio
 }
 
 
-#endif // !TARGET_OS_IPHONE
+#pragma mark -
+#pragma mark Bridge options
+
+
+static options bridgeOptions[] = {
+       { "mtu"       , NULL, isNumber     , &kSCPropNetEthernetMTU         , NULL, NULL },
+// xxx  { "+device"   , ... },
+// xxx  { "-device"   , ... },
+
+       { "?"         , NULL , isHelp     , NULL                            , NULL,
+           "\nBridge configuration commands\n\n"
+           " set interface [mtu n] [media type] [mediaopts opts]\n"
+       }
+};
+#define        N_BRIDGE_OPTIONS        (sizeof(bridgeOptions) / sizeof(bridgeOptions[0]))
+
+
+static Boolean
+set_interface_bridge(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(bridgeOptions, N_BRIDGE_OPTIONS, argc, argv, newConfiguration);
+       if (ok) {
+               // validate configuration
+               if (!validateMediaOptions(net_interface, newConfiguration)) {
+                       return FALSE;
+               }
+       }
+
+       return ok;
+}
 
 
 #pragma mark -
@@ -896,7 +1106,9 @@ static options airportOptions[] = {
        { "media"     , NULL, isString     , &kSCPropNetEthernetMediaSubType, NULL, NULL },
        { "mediaopt"  , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
 
-       { "?"         , NULL , isHelp     , NULL                            , NULL,
+       { "rank"      , NULL, isOther      , NULL                            , __doRank, NULL },
+
+       { "?"         , NULL, isHelp       , NULL                            , NULL,
            "\nAirPort configuration commands\n\n"
            " set interface [mtu n] [media type] [mediaopts opts]\n"
        }
@@ -932,12 +1144,63 @@ set_interface_airport(int argc, char **argv, CFMutableDictionaryRef newConfigura
 #pragma mark Ethernet options
 
 
+static int
+__doCapability(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+       Boolean ok      = FALSE;
+
+       if (argc < 1) {
+               SCPrint(TRUE, stdout,
+                       CFSTR("%s not specified\n"),
+                       description != NULL ? description : "enable/disable");
+               return -1;
+       }
+
+       if (strlen(argv[0]) == 0) {
+               ok = SCNetworkInterfaceSetCapability(net_interface, key, NULL);
+       } else if ((strcasecmp(argv[0], "disable") == 0) ||
+                  (strcasecmp(argv[0], "no"     ) == 0) ||
+                  (strcasecmp(argv[0], "off"    ) == 0) ||
+                  (strcasecmp(argv[0], "0"      ) == 0)) {
+               ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_0);
+       } else if ((strcasecmp(argv[0], "enable") == 0) ||
+                  (strcasecmp(argv[0], "yes"   ) == 0) ||
+                  (strcasecmp(argv[0], "on"    ) == 0) ||
+                  (strcasecmp(argv[0], "1"     ) == 0)) {
+               ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_1);
+       } else {
+               SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
+               return -1;
+       }
+
+       if (ok) {
+               updateInterfaceConfiguration(newConfiguration);
+       } else {
+               SCPrint(TRUE, stdout,
+                       CFSTR("%@ not updated: %s\n"),
+                       key,
+                       SCErrorString(SCError()));
+               return -1;
+       }
+
+       return 1;
+}
+
+
 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,
+       { "av"        , NULL, isOther      , &kSCPropNetEthernetCapabilityAV    , __doCapability, NULL },
+       { "lro"       , NULL, isOther      , &kSCPropNetEthernetCapabilityLRO   , __doCapability, NULL },
+       { "rxcsum"    , NULL, isOther      , &kSCPropNetEthernetCapabilityRXCSUM, __doCapability, NULL },
+       { "tso"       , NULL, isOther      , &kSCPropNetEthernetCapabilityTSO   , __doCapability, NULL },
+       { "txcsum"    , NULL, isOther      , &kSCPropNetEthernetCapabilityTXCSUM, __doCapability, NULL },
+
+       { "rank"      , NULL, isOther      , NULL                            , __doRank, NULL },
+
+       { "?"         , NULL, isHelp       , NULL                            , NULL,
            "\nEthernet configuration commands\n\n"
            " set interface [mtu n] [media type] [mediaopts opts]\n"
        }
@@ -973,45 +1236,24 @@ set_interface_ethernet(int argc, char **argv, CFMutableDictionaryRef newConfigur
 #pragma mark IPSec options
 
 
-static void
-replaceOne(const void *key, const void *value, void *context)
-{
-       CFMutableDictionaryRef  newConfiguration        = (CFMutableDictionaryRef)context;
-
-       CFDictionarySetValue(newConfiguration, key, value);
-       return;
-}
-
-
-static void
-updateInterfaceConfiguration(CFMutableDictionaryRef newConfiguration)
-{
-       CFDictionaryRef configuration;
-
-       CFDictionaryRemoveAllValues(newConfiguration);
-
-       configuration = SCNetworkInterfaceGetConfiguration(net_interface);
-       if (configuration != NULL) {
-               CFDictionaryApplyFunction(configuration, replaceOne, (void *)newConfiguration);
-       }
-
-       return;
-}
-
-
 static int
 __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
 {
+       CFStringRef     encryptionType;
+
        if (argc < 1) {
                SCPrint(TRUE, stdout, CFSTR("IPSec shared secret not specified\n"));
                return -1;
        }
 
+       encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption);
        if (strlen(argv[0]) > 0) {
-               CFStringRef     encryptionType;
-
-               encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption);
                if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -1020,10 +1262,12 @@ __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int
                        n = CFStringGetLength(str);
                        pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
                        CFDataSetLength(pw, n * sizeof(UniChar));
+                       /* ALIGN: CF aligns to at least >8 bytes */
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
@@ -1050,7 +1294,20 @@ __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int
                        return -1;
                }
        } else {
-               CFDictionaryRemoveValue(newConfiguration, key);
+               if (encryptionType == NULL) {
+                       CFDictionaryRemoveValue(newConfiguration, key);
+               } else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
+                       Boolean         ok;
+                       ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecSharedSecret);
+                       if (ok) {
+                               updateInterfaceConfiguration(newConfiguration);
+                       } else {
+                               return -1;
+                       }
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType);
+                       return -1;
+               }
        }
 
        return 1;
@@ -1086,16 +1343,21 @@ __doIPSecSharedSecretType(CFStringRef key, const char *description, void *info,
 static int
 __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
 {
+       CFStringRef     encryptionType;
+
        if (argc < 1) {
                SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password not specified\n"));
                return -1;
        }
 
+       encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption);
        if (strlen(argv[0]) > 0) {
-               CFStringRef     encryptionType;
-
-               encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption);
                if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -1104,10 +1366,12 @@ __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int
                        n = CFStringGetLength(str);
                        pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
                        CFDataSetLength(pw, n * sizeof(UniChar));
+                       /* ALIGN: CF aligns to at least >8 byte boundries */
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
@@ -1134,7 +1398,21 @@ __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int
                        return -1;
                }
        } else {
-               CFDictionaryRemoveValue(newConfiguration, key);
+               if (encryptionType == NULL) {
+                       CFDictionaryRemoveValue(newConfiguration, key);
+               } else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
+                       Boolean         ok;
+
+                       ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecXAuth);
+                       if (ok) {
+                               updateInterfaceConfiguration(newConfiguration);
+                       } else {
+                               return -1;
+                       }
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType);
+                       return -1;
+               }
        }
 
        return 1;
@@ -1167,7 +1445,7 @@ __doIPSecXAuthPasswordType(CFStringRef key, const char *description, void *info,
 }
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 __cleanupDomainName(CFStringRef domain)
 {
        CFMutableStringRef      newDomain;
@@ -1437,16 +1715,21 @@ set_interface_modem(int argc, char **argv, CFMutableDictionaryRef newConfigurati
 static int
 __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
 {
+       CFStringRef     encryptionType;
+
        if (argc < 1) {
                SCPrint(TRUE, stdout, CFSTR("PPP password not specified\n"));
                return -1;
        }
 
+       encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption);
        if (strlen(argv[0]) > 0) {
-               CFStringRef     encryptionType;
-
-               encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption);
                if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -1455,19 +1738,53 @@ __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, ch
                        n = CFStringGetLength(str);
                        pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
                        CFDataSetLength(pw, n * sizeof(UniChar));
+                       /* ALIGN: CF aligns to at least >8 byte boundries */
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
+               } else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
+                       Boolean         ok;
+                       CFDataRef       pw;
+                       CFStringRef     str;
+
+                       str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+                       pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
+                       ok = SCNetworkInterfaceSetPassword(net_interface,
+                                                          kSCNetworkInterfacePasswordTypePPP,
+                                                          pw,
+                                                          NULL);
+                       CFRelease(pw);
+                       CFRelease(str);
+                       if (ok) {
+                               updateInterfaceConfiguration(newConfiguration);
+                       } else {
+                               return -1;
+                       }
                } else {
                        SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
                        return -1;
                }
        } else {
-               CFDictionaryRemoveValue(newConfiguration, key);
+               if (encryptionType == NULL) {
+                       CFDictionaryRemoveValue(newConfiguration, key);
+               } else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
+                       Boolean         ok;
+
+                       ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypePPP);
+                       if (ok) {
+                               updateInterfaceConfiguration(newConfiguration);
+                       } else {
+                               return -1;
+                       }
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
+                       return -1;
+               }
        }
 
        return 1;
@@ -1739,9 +2056,6 @@ set_interface_ppp(int argc, char **argv, CFMutableDictionaryRef newConfiguration
 #pragma mark VLAN options
 
 
-#if    !TARGET_OS_IPHONE
-
-
 static Boolean
 set_interface_vlan(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
 {
@@ -1751,7 +2065,161 @@ SCPrint(TRUE, stdout, CFSTR("vlan interface management not yet supported\n"));
 }
 
 
-#endif // !TARGET_OS_IPHONE
+#pragma mark -
+#pragma mark VPN options
+
+
+static int
+__doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+       CFStringRef     encryptionType;
+
+       if (argc < 1) {
+               SCPrint(TRUE, stdout, CFSTR("VPN password not specified\n"));
+               return -1;
+       }
+
+       encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption);
+       if (strlen(argv[0]) > 0) {
+               if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
+                       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 *)(void *)CFDataGetMutableBytePtr(pw));
+                       CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
+
+                       CFDictionarySetValue(newConfiguration, key, pw);
+                       CFRelease(pw);
+               } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
+                       Boolean         ok;
+                       CFDataRef       pw;
+                       CFStringRef     str;
+
+                       str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+                       pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
+                       ok = SCNetworkInterfaceSetPassword(net_interface,
+                                                          kSCNetworkInterfacePasswordTypeVPN,
+                                                          pw,
+                                                          NULL);
+                       CFRelease(pw);
+                       CFRelease(str);
+                       if (ok) {
+                               updateInterfaceConfiguration(newConfiguration);
+                       } else {
+                               return -1;
+                       }
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("VPN password type \"%@\" not supported\n"), encryptionType);
+                       return -1;
+               }
+       } else {
+               if (encryptionType == NULL) {
+                       CFDictionaryRemoveValue(newConfiguration, key);
+               } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
+                       Boolean         ok;
+
+                       ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeVPN);
+                       if (ok) {
+                               updateInterfaceConfiguration(newConfiguration);
+                       } else {
+                               return -1;
+                       }
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
+                       return -1;
+               }
+       }
+
+       return 1;
+}
+
+
+static int
+__doVPNAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+       if (argc < 1) {
+               SCPrint(TRUE, stdout, CFSTR("VPN password type mode not specified\n"));
+               return -1;
+       }
+
+       if (strlen(argv[0]) > 0) {
+               if (strcasecmp(argv[0], "keychain") == 0) {
+                       CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionKeychain);
+               } else if (strcasecmp(argv[0], "prompt") == 0) {
+                       CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionPrompt);
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
+                       return -1;
+               }
+       } else {
+               CFDictionaryRemoveValue(newConfiguration, key);
+       }
+
+       // encryption type changed, reset password
+       CFDictionaryRemoveValue(newConfiguration, kSCPropNetVPNAuthPassword);
+
+       return 1;
+}
+
+
+static selections vpnAuthenticationMethodSelections[] = {
+       { CFSTR("Password")    , &kSCValNetVPNAuthenticationMethodPassword    , 0 },
+       { CFSTR("Certificate") , &kSCValNetVPNAuthenticationMethodCertificate , 0 },
+       { NULL                 , NULL                                         , 0 }
+};
+
+
+static options vpnOptions[] = {
+       { "AuthName"                  , "account"     , isString     , &kSCPropNetVPNAuthName                  , NULL                , NULL                                      },
+       {   "Account"                 , "account"     , isString     , &kSCPropNetVPNAuthName                  , NULL                , NULL                                      },
+       { "AuthPassword"              , "password"    , isOther      , &kSCPropNetVPNAuthPassword              , __doVPNAuthPW       , NULL                                      },
+       {   "Password"                , "password"    , isOther      , &kSCPropNetVPNAuthPassword              , __doVPNAuthPW       , NULL                                      },
+       { "AuthPasswordEncryption"    , "type"        , isOther      , &kSCPropNetVPNAuthPasswordEncryption    , __doVPNAuthPWType   , NULL                                      },
+       { "AuthenticationMethod"      , NULL          , isChooseOne  , &kSCPropNetVPNAuthenticationMethod      , NULL                , (void *)vpnAuthenticationMethodSelections },
+       { "ConnectTime"               , "?time"       , isNumber     , &kSCPropNetVPNConnectTime               , NULL                , NULL                                      },
+       { "DisconnectOnFastUserSwitch", NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnFastUserSwitch, NULL                , NULL                                      },
+       { "DisconnectOnIdle"          , NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnIdle          , NULL                , NULL                                      },
+       { "DisconnectOnIdleTimer"     , "timeout"     , isNumber     , &kSCPropNetVPNDisconnectOnIdleTimer     , NULL                , NULL                                      },
+       { "DisconnectOnLogout"        , NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnLogout        , NULL                , NULL                                      },
+       { "DisconnectOnSleep"         , NULL          , isBoolean    , &kSCPropNetVPNDisconnectOnSleep         , NULL                , NULL                                      },
+       { "Logfile"                   , "path"        , isString     , &kSCPropNetVPNLogfile                   , NULL                , NULL                                      },
+       { "MTU"                       , NULL          , isNumber     , &kSCPropNetVPNMTU                       , NULL                , NULL                                      },
+       { "RemoteAddress"             , "server"      , isString     , &kSCPropNetVPNRemoteAddress             , NULL                , NULL                                      },
+       {   "Server"                  , "server"      , isString     , &kSCPropNetVPNRemoteAddress             , NULL                , NULL                                      },
+       { "VerboseLogging"            , NULL          , isBoolean    , &kSCPropNetVPNVerboseLogging            , NULL                , NULL                                      },
+
+       // --- Help ---
+       { "?"                         , NULL          , isHelp       , NULL                                    , NULL                ,
+           "\nVPN configuration commands\n\n"
+           " set interface [Server server]\n"
+           " set interface [Account account]\n"
+           " set interface [Password password]\n"
+       }
+};
+#define        N_VPN_OPTIONS   (sizeof(vpnOptions) / sizeof(vpnOptions[0]))
+
+
+static Boolean
+set_interface_vpn(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+       Boolean ok;
+
+       ok = _process_options(vpnOptions, N_VPN_OPTIONS, argc, argv, newConfiguration);
+       return ok;
+}
 
 
 #pragma mark -
@@ -1803,12 +2271,14 @@ set_interface(int argc, char **argv)
                ok = set_interface_airport(argc, argv, newConfiguration);
        } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
                ok = set_interface_ppp(argc, argv, newConfiguration);
-#if    !TARGET_OS_IPHONE
        } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
                ok = set_interface_bond(argc, argv, newConfiguration);
+       } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
+               ok = set_interface_bridge(argc, argv, newConfiguration);
        } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
                ok = set_interface_vlan(argc, argv, newConfiguration);
-#endif // !TARGET_OS_IPHONE
+       } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
+               ok = set_interface_vpn(argc, argv, newConfiguration);
        } else {
                SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
        }
@@ -1871,7 +2341,7 @@ show_interface(int argc, char **argv)
 
 
 __private_extern__
-CFStringRef
+CF_RETURNS_RETAINED CFStringRef
 _interface_description(SCNetworkInterfaceRef interface)
 {
        CFMutableStringRef      description;