]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/LinkConfiguration.c
configd-53.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / LinkConfiguration.c
diff --git a/SystemConfiguration.fproj/LinkConfiguration.c b/SystemConfiguration.fproj/LinkConfiguration.c
new file mode 100644 (file)
index 0000000..159b4e0
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This 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 OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Modification History
+ *
+ * October 21, 2000            Allan Nathanson <ajn@apple.com>
+ * - initial revision
+ */
+
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPrivate.h>             // for SCLog()
+#include <SystemConfiguration/SCValidation.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/network/IONetworkInterface.h>
+#include <IOKit/network/IONetworkController.h>
+#include "dy_framework.h"
+
+
+static struct ifmedia_description ifm_subtype_shared_descriptions[] =
+    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_shared_option_descriptions[] =
+    IFM_SHARED_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
+
+
+static char *
+cfstring_to_cstring(CFStringRef cfstr, char *buf, int bufLen)
+{
+       CFIndex len     = CFStringGetLength(cfstr);
+
+       if (!buf) {
+               bufLen = len + 1;
+               buf = CFAllocatorAllocate(NULL, bufLen, 0);
+       }
+
+       if (len >= bufLen) {
+               len = bufLen - 1;
+       }
+
+       (void)CFStringGetBytes(cfstr,
+                              CFRangeMake(0, len),
+                              kCFStringEncodingASCII,
+                              0,
+                              FALSE,
+                              buf,
+                              bufLen,
+                              NULL);
+       buf[len] = '\0';
+
+       return buf;
+}
+
+
+
+static CFDictionaryRef
+__createMediaDictionary(int media_options, Boolean filter)
+{
+       CFMutableDictionaryRef  dict    = NULL;
+       int                     i;
+       CFMutableArrayRef       options = NULL;
+       CFStringRef             val;
+
+       if (IFM_TYPE(media_options) != IFM_ETHER) {
+               return NULL;
+       }
+
+       if (filter && (IFM_SUBTYPE(media_options) == IFM_NONE)) {
+               return NULL;    /* filter */
+       }
+
+       dict = CFDictionaryCreateMutable(NULL,
+                                        0,
+                                        &kCFTypeDictionaryKeyCallBacks,
+                                        &kCFTypeDictionaryValueCallBacks);
+
+       /* subtype */
+
+       val = NULL;
+       for (i=0; !val && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
+               if (IFM_SUBTYPE(media_options) == ifm_subtype_shared_descriptions[i].ifmt_word) {
+                       val = CFStringCreateWithCString(NULL,
+                                                       ifm_subtype_shared_descriptions[i].ifmt_string,
+                                                       kCFStringEncodingASCII);
+                       break;
+               }
+       }
+
+       for (i=0; !val && ifm_subtype_ethernet_descriptions[i].ifmt_string; i++) {
+               if (IFM_SUBTYPE(media_options) == ifm_subtype_ethernet_descriptions[i].ifmt_word) {
+                       val = CFStringCreateWithCString(NULL,
+                                                       ifm_subtype_ethernet_descriptions[i].ifmt_string,
+                                                       kCFStringEncodingASCII);
+                       break;
+               }
+       }
+
+       if (val) {
+               CFDictionaryAddValue(dict, kSCPropNetEthernetMediaSubType, val);
+               CFRelease(val);
+       }
+
+       /* options */
+
+       options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+       while (IFM_OPTIONS(media_options) != 0) {
+               if (filter && (IFM_OPTIONS(media_options) & IFM_LOOP)) {
+                       media_options &= ~IFM_LOOP;     /* filter */
+                       continue;
+               }
+
+               val = NULL;
+               for (i=0; !val && ifm_shared_option_descriptions[i].ifmt_string; i++) {
+                       if (IFM_OPTIONS(media_options) & ifm_shared_option_descriptions[i].ifmt_word) {
+                               val = CFStringCreateWithCString(NULL,
+                                                               ifm_shared_option_descriptions[i].ifmt_string,
+                                                               kCFStringEncodingASCII);
+                               media_options &= ~ifm_shared_option_descriptions[i].ifmt_word;
+                               break;
+                       }
+               }
+
+               for (i=0; !val && ifm_subtype_ethernet_option_descriptions[i].ifmt_string; i++) {
+                       if (IFM_OPTIONS(media_options) & ifm_subtype_ethernet_option_descriptions[i].ifmt_word) {
+                               val = CFStringCreateWithCString(NULL,
+                                                               ifm_subtype_ethernet_option_descriptions[i].ifmt_string,
+                                                               kCFStringEncodingASCII);
+                               media_options &= ~ifm_shared_option_descriptions[i].ifmt_word;
+                               break;
+                       }
+               }
+
+               if (val) {
+                       CFArrayAppendValue(options, val);
+                       CFRelease(val);
+               }
+       }
+
+       CFDictionaryAddValue(dict, kSCPropNetEthernetMediaOptions, options);
+       CFRelease(options);
+
+       return dict;
+}
+
+
+int
+__createMediaOptions(CFDictionaryRef media_options)
+{
+       CFIndex         i;
+       Boolean         match;
+       int             ifm_new = IFM_ETHER;
+       CFArrayRef      options;
+       char            *str;
+       CFStringRef     val;
+
+       /* set subtype */
+
+       val = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaSubType);
+       if (!isA_CFString(val)) {
+               return -1;
+       }
+
+       str = cfstring_to_cstring(val, NULL, 0);
+       if (!str) {
+               return -1;
+       }
+
+       match = FALSE;
+       for (i=0; !match && ifm_subtype_shared_descriptions[i].ifmt_string; i++) {
+               if (strcasecmp(str, ifm_subtype_shared_descriptions[i].ifmt_string) == 0) {
+                       ifm_new |= ifm_subtype_shared_descriptions[i].ifmt_word;
+                       match = TRUE;
+                       break;
+               }
+       }
+
+       for (i=0; !match && ifm_subtype_ethernet_descriptions[i].ifmt_string; i++) {
+               if (strcasecmp(str, ifm_subtype_ethernet_descriptions[i].ifmt_string) == 0) {
+                       ifm_new |= ifm_subtype_ethernet_descriptions[i].ifmt_word;
+                       match = TRUE;
+                       break;
+               }
+       }
+
+       CFAllocatorDeallocate(NULL, str);
+
+       if (!match) {
+               return -1;      /* if no subtype */
+       }
+
+       /* set options */
+
+       options = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaOptions);
+       if (!isA_CFArray(options)) {
+               return -1;
+       }
+
+       for (i=0; i<CFArrayGetCount(options); i++) {
+               CFIndex         j;
+
+               val = CFArrayGetValueAtIndex(options, i);
+               if (!isA_CFString(val)) {
+                       return -1;
+               }
+
+               str = cfstring_to_cstring(val, NULL, 0);
+               if (!str) {
+                       return -1;
+               }
+
+
+               match = FALSE;
+               for (j=0; !match && ifm_shared_option_descriptions[j].ifmt_string; j++) {
+                       if (strcasecmp(str, ifm_shared_option_descriptions[j].ifmt_string) == 0) {
+                               ifm_new |= ifm_shared_option_descriptions[j].ifmt_word;
+                               match = TRUE;
+                               break;
+                       }
+               }
+
+               for (j=0; !match && ifm_subtype_ethernet_option_descriptions[j].ifmt_string; j++) {
+                       if (strcasecmp(str, ifm_subtype_ethernet_option_descriptions[j].ifmt_string) == 0) {
+                               ifm_new |= ifm_subtype_ethernet_option_descriptions[j].ifmt_word;
+                               match = TRUE;
+                               break;
+                       }
+               }
+
+               CFAllocatorDeallocate(NULL, str);
+
+               if (!match) {
+                       return -1;      /* if no option */
+               }
+       }
+
+       return ifm_new;
+}
+
+
+Boolean
+NetworkInterfaceCopyMediaOptions(CFStringRef           interface,
+                                CFDictionaryRef        *current,
+                                CFDictionaryRef        *active,
+                                CFArrayRef             *available,
+                                Boolean                filter)
+{
+       int                     i;
+       struct ifmediareq       ifm;
+       int                     *media_list     = NULL;
+       Boolean                 ok              = FALSE;
+       int                     sock            = -1;
+
+       bzero((char *)&ifm, sizeof(ifm));
+
+       (void)cfstring_to_cstring(interface, ifm.ifm_name, sizeof(ifm.ifm_name));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock < 0) {
+               SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
+               goto done;
+       }
+
+       if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) {
+//             SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
+               goto done;
+       }
+
+       if (ifm.ifm_count > 0) {
+               media_list = (int *)CFAllocatorAllocate(NULL, ifm.ifm_count * sizeof(int), 0);
+               ifm.ifm_ulist = media_list;
+               if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) {
+                       SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
+                       goto done;
+               }
+       }
+
+       if (active)     *active    = NULL;
+       if (current)    *current   = NULL;
+       if (available) {
+               CFMutableArrayRef       media_options;
+
+               media_options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+               for (i=0; i<ifm.ifm_count; i++) {
+                       CFDictionaryRef options;
+
+                       options = __createMediaDictionary(media_list[i], filter);
+                       if (!options) {
+                               continue;
+                       }
+
+                       if (active  && (*active == NULL)  && (ifm.ifm_active == media_list[i])) {
+                               *active  = CFRetain(options);
+                       }
+
+                       if (current && (*current == NULL) && (ifm.ifm_current == media_list[i])) {
+                               *current = CFRetain(options);
+                       }
+
+                       if (!CFArrayContainsValue(media_options, CFRangeMake(0, CFArrayGetCount(media_options)), options)) {
+                               CFArrayAppendValue(media_options, options);
+                       }
+
+                       CFRelease(options);
+               }
+               *available = (CFArrayRef)media_options;
+       }
+
+       if (active  && (*active == NULL)) {
+               *active = __createMediaDictionary(ifm.ifm_active, FALSE);
+       }
+
+       if (current && (*current == NULL)) {
+               if (active && (ifm.ifm_active == ifm.ifm_current)) {
+                       if (*active)    *current = CFRetain(active);
+               } else {
+                       *current = __createMediaDictionary(ifm.ifm_current, FALSE);
+               }
+       }
+
+       ok = TRUE;
+
+    done :
+
+       if (sock >= 0)  (void)close(sock);
+       if (media_list) CFAllocatorDeallocate(NULL, media_list);
+
+       return ok;
+}
+
+
+CFArrayRef
+NetworkInterfaceCopyMediaSubTypes(CFArrayRef   available)
+{
+       CFIndex                 i;
+       CFMutableArrayRef       subTypes;
+
+       if (!isA_CFArray(available)) {
+               return NULL;
+       }
+
+       subTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       for (i=0; i<CFArrayGetCount(available); i++) {
+               CFDictionaryRef options;
+               CFStringRef     subType;
+
+               options = CFArrayGetValueAtIndex(available, i);
+               if (!isA_CFDictionary(options)) {
+                       continue;
+               }
+
+               subType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
+               if (!isA_CFString(subType)) {
+                       continue;
+               }
+
+               if (!CFArrayContainsValue(subTypes, CFRangeMake(0, CFArrayGetCount(subTypes)), subType)) {
+                       CFArrayAppendValue(subTypes, subType);
+               }
+       }
+
+       if (CFArrayGetCount(subTypes) == 0) {
+               CFRelease(subTypes);
+               subTypes = NULL;
+       }
+
+       return subTypes;
+}
+
+
+CFArrayRef
+NetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef     available,
+                                       CFStringRef     subType)
+{
+       CFIndex                 i;
+       CFMutableArrayRef       subTypeOptions;
+
+       if (!isA_CFArray(available)) {
+               return NULL;
+       }
+
+       subTypeOptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       for (i=0; i<CFArrayGetCount(available); i++) {
+               CFDictionaryRef options;
+               CFArrayRef      mediaOptions;
+               CFStringRef     mediaSubType;
+
+               options = CFArrayGetValueAtIndex(available, i);
+               if (!isA_CFDictionary(options)) {
+                       continue;
+               }
+
+               mediaSubType = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
+               if (!isA_CFString(mediaSubType) || !CFEqual(subType, mediaSubType)) {
+                       continue;
+               }
+
+               mediaOptions = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
+               if (!isA_CFArray(mediaOptions)) {
+                       continue;
+               }
+
+               if (!CFArrayContainsValue(subTypeOptions, CFRangeMake(0, CFArrayGetCount(subTypeOptions)), mediaOptions)) {
+                       CFArrayAppendValue(subTypeOptions, mediaOptions);
+               }
+       }
+
+       if (CFArrayGetCount(subTypeOptions) == 0) {
+               CFRelease(subTypeOptions);
+               subTypeOptions = NULL;
+       }
+
+       return subTypeOptions;
+}
+
+
+Boolean
+NetworkInterfaceCopyMTU(CFStringRef    interface,
+                       int             *mtu_cur,
+                       int             *mtu_min,
+                       int             *mtu_max)
+{
+       struct ifreq    ifr;
+       Boolean         ok      = FALSE;
+       int             sock    = -1;
+
+       bzero((char *)&ifr, sizeof(ifr));
+       (void)cfstring_to_cstring(interface, ifr.ifr_name, sizeof(ifr.ifr_name));
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock < 0) {
+               SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
+               goto done;
+       }
+
+       if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
+//             SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMTU) failed: %s"), strerror(errno));
+               goto done;
+       }
+
+       if (mtu_cur)    *mtu_cur = ifr.ifr_mtu;
+
+       /* get valid MTU range */
+
+       if (mtu_min || mtu_max) {
+               char                    ifName[IFNAMSIZ+1];
+               int                     ifType          = 0;
+               io_iterator_t           io_iter         = 0;
+               io_registry_entry_t     io_interface    = 0;
+               io_registry_entry_t     io_controller   = 0;
+               kern_return_t           kr;
+               mach_port_t             masterPort      = MACH_PORT_NULL;
+               CFMutableDictionaryRef  matchingDict;
+
+               /* assume that we don't know */
+
+               if (mtu_min) *mtu_min = -1;
+               if (mtu_max) *mtu_max = -1;
+
+               /* look for a matching interface in the IORegistry */
+
+               (void)cfstring_to_cstring(interface, ifName, sizeof(ifName));
+               matchingDict = IOBSDNameMatching(masterPort, 0, ifName);
+               if (matchingDict) {
+                       /* Note: IOServiceGetMatchingServices consumes a reference on the 'matchingDict' */
+                       kr = IOServiceGetMatchingServices(masterPort, matchingDict, &io_iter);
+                       if ((kr == KERN_SUCCESS) && io_iter) {
+                           /* should only have a single match */
+                           io_interface = IOIteratorNext(io_iter);
+                       }
+                       if (io_iter)    IOObjectRelease(io_iter);
+               }
+
+               /* found an interface with the given BSD name, get its parent */
+
+               if (io_interface) {
+                       CFNumberRef     num;
+
+                       /*
+                        * get the interface type
+                        */
+                       num = IORegistryEntryCreateCFProperty(io_interface, CFSTR(kIOInterfaceType), NULL, kNilOptions);
+                       if (num) {
+                               if (isA_CFNumber(num)) {
+                                       CFNumberGetValue(num, kCFNumberIntType, &ifType);
+                               }
+                               CFRelease(num);
+                      }
+
+                       /*
+                        * ...and the property we are REALLY interested is in the controller,
+                        * which is the parent of the interface object.
+                        */
+                       (void)IORegistryEntryGetParentEntry(io_interface, kIOServicePlane, &io_controller);
+
+                       IOObjectRelease(io_interface);
+               }
+
+               if (io_controller) {
+                       CFNumberRef     num;
+
+                       num = IORegistryEntryCreateCFProperty(io_controller, CFSTR(kIOMaxPacketSize), NULL, kNilOptions);
+                       if (num) {
+                               if (isA_CFNumber(num)) {
+                                       int     value;
+
+                                       /*
+                                        * Get the value and subtract the FCS bytes and Ethernet header
+                                        * sizes from the maximum frame size reported by the controller
+                                        * to get the MTU size. The 14 byte media header can be found
+                                        * in the registry, but not the size for the trailing FCS bytes.
+                                        */
+                                       CFNumberGetValue(num, kCFNumberIntType, &value);
+
+                                       if (ifType == IFT_ETHER) {
+                                               value -= (ETHER_HDR_LEN + ETHER_CRC_LEN);
+                                       }
+
+                                       if (mtu_min)    *mtu_min = IF_MINMTU;
+                                       if (mtu_max)    *mtu_max = value;
+                               }
+                               CFRelease(num);
+                       }
+
+                       IOObjectRelease(io_controller);
+               }
+       }
+
+       ok = TRUE;
+
+    done :
+
+       if (sock >= 0)  (void)close(sock);
+
+       return ok;
+}