Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
34 kB · 1280 lines
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281/* * Copyright (c) 2002-2007, 2010, 2011, 2013, 2015-2019 Apple 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 * * October 21, 2000 Allan Nathanson <ajn@apple.com> * - initial revision */
#include <unistd.h>#define KERNEL_PRIVATE#include <sys/ioctl.h>#undef KERNEL_PRIVATE#include <sys/socket.h>#include <net/ethernet.h>#include <net/if.h>#include <net/if_vlan_var.h>#include <net/if_media.h>#include <net/if_types.h>#include <netinet/in.h>#include <netinet/ip6.h> // for IPV6_MMTU
#include "SCNetworkConfigurationInternal.h" // for __SCNetworkInterfaceCreatePrivate
#include <IOKit/IOKitLib.h>#include <IOKit/network/IONetworkInterface.h>#include <IOKit/network/IONetworkController.h>#include "dy_framework.h"
#pragma mark -#pragma mark Capabilities
// the following table needs to keep the capabilitiy names and values// between the <SystemConfiguration/SCSchemaDefinitionsPrivate.h> and// <net/if.h> headers in sync.static const struct { const CFStringRef *name; Boolean readwrite; int val;} capabilityMappings[] = {#ifdef SIOCGIFCAP { &kSCPropNetEthernetCapabilityRXCSUM, TRUE, IFCAP_RXCSUM }, // can offload checksum on RX { &kSCPropNetEthernetCapabilityTXCSUM, TRUE, IFCAP_TXCSUM }, // can offload checksum on TX { &kSCPropNetEthernetCapabilityVLAN_MTU, FALSE, IFCAP_VLAN_MTU }, // VLAN-compatible MTU { &kSCPropNetEthernetCapabilityVLAN_HWTAGGING, FALSE, IFCAP_VLAN_HWTAGGING }, // hardware VLAN tag support { &kSCPropNetEthernetCapabilityJUMBO_MTU, FALSE, IFCAP_JUMBO_MTU }, // 9000 byte MTU supported { &kSCPropNetEthernetCapabilityTSO, TRUE, IFCAP_TSO }, // can do TCP/TCP6 Segmentation Offload { &kSCPropNetEthernetCapabilityTSO4, FALSE, IFCAP_TSO4 }, // can do TCP Segmentation Offload { &kSCPropNetEthernetCapabilityTSO6, FALSE, IFCAP_TSO6 }, // can do TCP6 Segmentation Offload { &kSCPropNetEthernetCapabilityLRO, TRUE, IFCAP_LRO }, // can do Large Receive Offload { &kSCPropNetEthernetCapabilityAV, TRUE, IFCAP_AV }, // can do 802.1 AV Bridging#endif // SIOCGIFCAP};
static CFIndexfindCapability(CFStringRef capability){ for (size_t i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) { if (CFEqual(capability, *capabilityMappings[i].name)) { return i; } }
return kCFNotFound;}
static Boolean__getCapabilities(CFStringRef interfaceName, int *current, int *available){#ifdef SIOCGIFCAP struct ifreq ifr; Boolean ok = FALSE; int sock = -1;
memset((void *)&ifr, 0, sizeof(ifr)); if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) { SC_log(LOG_NOTICE, "could not convert interface name"); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { _SCErrorSet(errno); SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); return FALSE; }
if (ioctl(sock, SIOCGIFCAP, (caddr_t)&ifr) == -1) { _SCErrorSet(errno); switch (errno) { case EBUSY : case ENXIO : break; default : SC_log(LOG_NOTICE, "ioctl(SIOCGIFCAP) failed: %s", strerror(errno)); } goto done; }
if (current != NULL) *current = ifr.ifr_curcap; if (available != NULL) *available = ifr.ifr_reqcap;
ok = TRUE;
done :
(void)close(sock); return ok;#else // SIOCGIFCAP if (current != NULL) *current = 0; if (available != NULL) *available = 0; return TRUE;#endif // SIOCGIFCAP}
int__SCNetworkInterfaceCreateCapabilities(SCNetworkInterfaceRef interface, int capability_base, CFDictionaryRef capability_options){ int cap_available = 0; int cap_current = capability_base; CFStringRef interfaceName;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); goto done; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { _SCErrorSet(kSCStatusInvalidArgument); goto done; }
if (!__getCapabilities(interfaceName, (capability_base == -1) ? &cap_current : NULL, &cap_available)) { goto done; }
if (cap_available == 0) { goto done; }
if (capability_options == NULL) { goto done; }
for (size_t i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) { int cap_val; CFTypeRef val;
if (((cap_available & capabilityMappings[i].val) != 0) && capabilityMappings[i].readwrite && CFDictionaryGetValueIfPresent(capability_options, *capabilityMappings[i].name, &val) && isA_CFNumber(val) && CFNumberGetValue(val, kCFNumberIntType, &cap_val)) { // update capability if (cap_val != 0) { cap_current |= (cap_available & capabilityMappings[i].val); } else { cap_current &= ~capabilityMappings[i].val; }
// don't process again cap_available &= ~capabilityMappings[i].val; } }
done :
return cap_current;}
CFTypeRefSCNetworkInterfaceCopyCapability(SCNetworkInterfaceRef interface, CFStringRef capability){ int cap_current = 0; int cap_available = 0; int cap_val; CFStringRef interfaceName; CFTypeRef val = NULL;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
if (!__getCapabilities(interfaceName, &cap_current, &cap_available)) { return NULL; }
if (capability == NULL) { CFMutableDictionaryRef all = NULL;
// if ALL capabilities requested for (size_t i = 0; i < sizeof(capabilityMappings) / sizeof(capabilityMappings[0]); i++) { if ((cap_available & capabilityMappings[i].val) == capabilityMappings[i].val) { if (all == NULL) { all = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } cap_val = ((cap_current & capabilityMappings[i].val) == capabilityMappings[i].val) ? 1 : 0; val = CFNumberCreate(NULL, kCFNumberIntType, &cap_val); CFDictionarySetValue(all, *capabilityMappings[i].name, val); CFRelease(val); cap_available &= ~capabilityMappings[i].val; } }
val = all; } else { CFIndex i;
i = findCapability(capability); if (i == kCFNotFound) { // if unknown capability _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
if ((cap_available & capabilityMappings[i].val) != capabilityMappings[i].val) { // if capability not available _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
cap_val = ((cap_current & capabilityMappings[i].val) == capabilityMappings[i].val) ? 1 : 0; val = CFNumberCreate(NULL, kCFNumberIntType, &cap_val); }
return val;}
BooleanSCNetworkInterfaceSetCapability(SCNetworkInterfaceRef interface, CFStringRef capability, CFTypeRef newValue){ int cap_available = 0; CFDictionaryRef configuration; CFIndex i; CFStringRef interfaceName; CFMutableDictionaryRef newConfiguration = NULL; Boolean ok = FALSE;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { // if no interface name _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
i = findCapability(capability); if (i == kCFNotFound) { // if unknown capability _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!capabilityMappings[i].readwrite) { // if not read-write _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if ((newValue != NULL) && !isA_CFNumber(newValue)) { // all values must (for now) be CFNumber[0 or 1]'s _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!__getCapabilities(interfaceName, NULL, &cap_available)) { return FALSE; }
if ((cap_available & capabilityMappings[i].val) == 0) { // if capability not available _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
configuration = SCNetworkInterfaceGetConfiguration(interface); if (configuration == NULL) { newConfiguration = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } else { newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); }
if ((newValue != NULL)) { CFDictionarySetValue(newConfiguration, capability, newValue); } else { CFDictionaryRemoveValue(newConfiguration, capability); if (CFDictionaryGetCount(newConfiguration) == 0) { CFRelease(newConfiguration); newConfiguration = NULL; } }
ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration); if (newConfiguration != NULL) CFRelease(newConfiguration);
return ok;}
#pragma mark -#pragma mark Media Options
static const struct ifmedia_description ifm_subtype_shared_descriptions[] = IFM_SUBTYPE_SHARED_DESCRIPTIONS;
static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] = IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
static const struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
static const struct ifmedia_description ifm_shared_option_descriptions[] = IFM_SHARED_OPTION_DESCRIPTIONS;
static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
static void__freeMediaList(struct ifmediareq *ifm){ if (ifm->ifm_ulist != NULL) CFAllocatorDeallocate(NULL, ifm->ifm_ulist); CFAllocatorDeallocate(NULL, ifm); return;}
static struct ifmediareq *__copyMediaList(CFStringRef interfaceName){ struct ifmediareq *ifm; Boolean ok = FALSE; int sock = -1;
ifm = (struct ifmediareq *)CFAllocatorAllocate(NULL, sizeof(struct ifmediareq), 0); memset((void *)ifm, 0, sizeof(*ifm));
if (_SC_cfstring_to_cstring(interfaceName, ifm->ifm_name, sizeof(ifm->ifm_name), kCFStringEncodingASCII) == NULL) { SC_log(LOG_NOTICE, "could not convert interface name"); goto done; }
sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); goto done; }
if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)ifm) == -1) {// SC_log(LOG_NOTICE, "ioctl(SIOCGIFXMEDIA) failed: %s", strerror(errno)); goto done; }
if (ifm->ifm_count > 0) { ifm->ifm_ulist = (int *)CFAllocatorAllocate(NULL, ifm->ifm_count * sizeof(int), 0); if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)ifm) == -1) { SC_log(LOG_NOTICE, "ioctl(SIOCGIFXMEDIA) failed: %s", strerror(errno)); goto done; } }
ok = TRUE;
done :
if (sock != -1) (void)close(sock); if (!ok) { __freeMediaList(ifm); ifm = NULL; _SCErrorSet(kSCStatusFailed); } return ifm;}
static CFDictionaryRef__createMediaDictionary(int media_options, Boolean filter){ CFMutableDictionaryRef dict = NULL; int i; const struct ifmedia_description *option_descriptions = NULL; CFMutableArrayRef options = NULL; const struct ifmedia_description *subtype_descriptions = NULL; CFStringRef val;
if (filter && ((IFM_SUBTYPE(media_options) == IFM_NONE) || ((IFM_OPTIONS(media_options) & IFM_LOOP) != 0))) { return NULL; /* filter */ }
switch (IFM_TYPE(media_options)) { case IFM_ETHER : option_descriptions = ifm_subtype_ethernet_option_descriptions; subtype_descriptions = ifm_subtype_ethernet_descriptions; break; case IFM_IEEE80211 : option_descriptions = ifm_subtype_ieee80211_option_descriptions; subtype_descriptions = ifm_subtype_ieee80211_descriptions; break; default : return NULL; }
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; } }
if (subtype_descriptions != NULL) { for (i = 0; !val && subtype_descriptions[i].ifmt_string; i++) { if (IFM_SUBTYPE(media_options) == subtype_descriptions[i].ifmt_word) { val = CFStringCreateWithCString(NULL, subtype_descriptions[i].ifmt_string, kCFStringEncodingASCII); break; } } }
if (val) { CFDictionaryAddValue(dict, kSCPropNetEthernetMediaSubType, val); CFRelease(val); }
/* options */
options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (i = 0; (IFM_OPTIONS(media_options) != 0) && (ifm_shared_option_descriptions[i].ifmt_string != NULL); i++) { if ((media_options & ifm_shared_option_descriptions[i].ifmt_word) != 0) { val = CFStringCreateWithCString(NULL, ifm_shared_option_descriptions[i].ifmt_string, kCFStringEncodingASCII); CFArrayAppendValue(options, val); CFRelease(val);
media_options &= ~ifm_shared_option_descriptions[i].ifmt_word; } }
if (option_descriptions != NULL) { for (i = 0; (IFM_OPTIONS(media_options) != 0) && (option_descriptions[i].ifmt_string != NULL); i++) { if ((media_options & option_descriptions[i].ifmt_word) != 0) { val = CFStringCreateWithCString(NULL, option_descriptions[i].ifmt_string, kCFStringEncodingASCII); CFArrayAppendValue(options, val); CFRelease(val);
media_options &= ~option_descriptions[i].ifmt_word; } } }
CFDictionaryAddValue(dict, kSCPropNetEthernetMediaOptions, options); CFRelease(options);
return dict;}
int__SCNetworkInterfaceCreateMediaOptions(SCNetworkInterfaceRef interface, CFDictionaryRef media_options){ CFIndex i; struct ifmediareq *ifm; int ifm_new = -1; CFStringRef interfaceName; Boolean match; CFIndex n; const struct ifmedia_description *option_descriptions = NULL; CFArrayRef options; char *str; const struct ifmedia_description *subtype_descriptions = NULL; CFStringRef val;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return -1; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return -1; }
/* set type */
ifm = __copyMediaList(interfaceName); if (ifm != NULL) { if (ifm->ifm_count > 0) { ifm_new = IFM_TYPE(ifm->ifm_ulist[0]); } __freeMediaList(ifm); }
if (ifm_new == -1) { // if we cannot determine the media type for the interface return -1; }
switch (IFM_TYPE(ifm_new)) { case IFM_ETHER : option_descriptions = ifm_subtype_ethernet_option_descriptions; subtype_descriptions = ifm_subtype_ethernet_descriptions; break; case IFM_IEEE80211 : option_descriptions = ifm_subtype_ieee80211_option_descriptions; subtype_descriptions = ifm_subtype_ieee80211_descriptions; break; }
/* set subtype */
val = CFDictionaryGetValue(media_options, kSCPropNetEthernetMediaSubType); if (!isA_CFString(val)) { return -1; }
str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII); if (str == NULL) { 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; } }
if (subtype_descriptions != NULL) { for (i = 0; !match && subtype_descriptions[i].ifmt_string; i++) { if (strcasecmp(str, subtype_descriptions[i].ifmt_string) == 0) { ifm_new |= subtype_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; }
n = CFArrayGetCount(options); for (i = 0; i < n; i++) { CFIndex j;
val = CFArrayGetValueAtIndex(options, i); if (!isA_CFString(val)) { return -1; }
str = _SC_cfstring_to_cstring(val, NULL, 0, kCFStringEncodingASCII); if (str == NULL) { 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; } }
if (option_descriptions != NULL) { for (j = 0; !match && option_descriptions[j].ifmt_string; j++) { if (strcasecmp(str, option_descriptions[j].ifmt_string) == 0) { ifm_new |= option_descriptions[j].ifmt_word; match = TRUE; break; } } }
CFAllocatorDeallocate(NULL, str);
if (!match) { return -1; /* if no option */ } }
return ifm_new;}
BooleanSCNetworkInterfaceCopyMediaOptions(SCNetworkInterfaceRef interface, CFDictionaryRef *current, CFDictionaryRef *active, CFArrayRef *available, Boolean filter){ int i; struct ifmediareq *ifm; CFStringRef interfaceName;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
ifm = __copyMediaList(interfaceName); if (ifm == NULL) { return FALSE; }
if (active != NULL) *active = NULL; if (current != NULL) *current = NULL; if (available != NULL) { CFMutableArrayRef media_options;
media_options = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); for (i = 0; i < ifm->ifm_count; i++) { CFDictionaryRef options;
options = __createMediaDictionary(ifm->ifm_ulist[i], filter); if (options == NULL) { continue; }
if ((active != NULL) && (*active == NULL) && (ifm->ifm_active == ifm->ifm_ulist[i])) { *active = CFRetain(options); }
if ((current != NULL) && (*current == NULL) && (ifm->ifm_current == ifm->ifm_ulist[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 != NULL) && (*active == NULL)) { *active = __createMediaDictionary(ifm->ifm_active, FALSE); }
if ((current != NULL) && (*current == NULL)) { if ((active != NULL) && (ifm->ifm_active == ifm->ifm_current)) { if (*active != NULL) *current = CFRetain(*active); } else { *current = __createMediaDictionary(ifm->ifm_current, FALSE); } }
__freeMediaList(ifm); return TRUE;}
CFArrayRefSCNetworkInterfaceCopyMediaSubTypes(CFArrayRef available){ CFIndex i; CFIndex n; CFMutableArrayRef subTypes;
if (!isA_CFArray(available)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
subTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = CFArrayGetCount(available); for (i = 0; i < n; 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; _SCErrorSet(kSCStatusOK); }
return subTypes;}
CFArrayRefSCNetworkInterfaceCopyMediaSubTypeOptions(CFArrayRef available, CFStringRef subType){ CFIndex i; CFIndex n; CFMutableArrayRef subTypeOptions;
if (!isA_CFArray(available)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
subTypeOptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = CFArrayGetCount(available); for (i = 0; i < n; 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; _SCErrorSet(kSCStatusOK); }
return subTypeOptions;}
Boolean_SCNetworkInterfaceIsPhysicalEthernet(SCNetworkInterfaceRef interface){ int i; struct ifmediareq *ifm; CFStringRef interfaceName; Boolean realEthernet = FALSE;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
ifm = __copyMediaList(interfaceName); if (ifm == NULL) { CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface); if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet) && !_SCNetworkInterfaceIsTethered(interface) && !_SCNetworkInterfaceIsBluetoothPAN(interface)) { // if likely physical ethernet interface return TRUE; } return FALSE; } _SCErrorSet(kSCStatusOK); if (IFM_TYPE(ifm->ifm_current) != IFM_ETHER) { goto done; } if (ifm->ifm_count == 1 && IFM_SUBTYPE(ifm->ifm_ulist[0]) == IFM_AUTO) { /* only support autoselect, not really ethernet */ goto done; } for (i = 0; i < ifm->ifm_count; i++) { if ((ifm->ifm_ulist[i] & IFM_FDX) != 0) { realEthernet = TRUE; break; } } done: __freeMediaList(ifm); return (realEthernet);}
static Boolean__getIOMTULimits(char ifr_name[IFNAMSIZ], int *mtu_min, int *mtu_max){ 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; static mach_port_t masterPort = MACH_PORT_NULL; CFMutableDictionaryRef matchingDict;
/* look for a matching interface in the IORegistry */
if (masterPort == MACH_PORT_NULL) { kr = IOMasterPort(MACH_PORT_NULL, &masterPort); if (kr != KERN_SUCCESS) { return FALSE; } }
matchingDict = IOBSDNameMatching(masterPort, 0, ifr_name); 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); }
if (io_interface) { CFNumberRef num;
/* * found an interface, 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); } else { /* if no matching interface */ return FALSE; }
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); }
return TRUE;}
BooleanSCNetworkInterfaceCopyMTU(SCNetworkInterfaceRef interface, int *mtu_cur, int *mtu_min, int *mtu_max){ struct ifreq ifr; CFStringRef interfaceName; Boolean ok = FALSE; int sock = -1;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
interfaceName = SCNetworkInterfaceGetBSDName(interface); if (interfaceName == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
memset((void *)&ifr, 0, sizeof(ifr)); if (_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII) == NULL) { SC_log(LOG_NOTICE, "could not convert interface name"); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { _SCErrorSet(errno); SC_log(LOG_ERR, "socket() failed: %s", strerror(errno)); return FALSE; }
if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) == -1) { _SCErrorSet(errno);// SC_log(LOG_NOTICE, "ioctl(SIOCGIFMTU) failed: %s", strerror(errno)); goto done; }
if (mtu_cur) *mtu_cur = ifr.ifr_mtu; if (mtu_min) *mtu_min = ifr.ifr_mtu; if (mtu_max) *mtu_max = ifr.ifr_mtu;
/* get valid MTU range */
if (mtu_min != NULL || mtu_max != NULL) { if (ioctl(sock, SIOCGIFDEVMTU, (caddr_t)&ifr) == 0) { struct ifdevmtu * devmtu_p;
devmtu_p = &ifr.ifr_devmtu; if (mtu_min != NULL) { *mtu_min = (devmtu_p->ifdm_min > IF_MINMTU) ? devmtu_p->ifdm_min : IF_MINMTU; } if (mtu_max != NULL) { *mtu_max = devmtu_p->ifdm_max; } } else { ok = __getIOMTULimits(ifr.ifr_name, mtu_min, mtu_max); if (!ok) { CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface); if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { CFIndex i; CFArrayRef members; CFIndex n;
members = SCBridgeInterfaceGetMemberInterfaces(interface); n = (members != NULL) ? CFArrayGetCount(members) : 0; if (n > 1) { if (mtu_min) *mtu_min = IF_MINMTU; if (mtu_max) *mtu_max = IF_MAXMTU; } for (i = 0; i < n; i++) { SCNetworkInterfaceRef member; int member_mtu_min; int member_mtu_max;
member = CFArrayGetValueAtIndex(members, i); ok = SCNetworkInterfaceCopyMTU(member, NULL, &member_mtu_min, &member_mtu_max); if (ok) { if ((mtu_min != NULL) && (*mtu_min < member_mtu_min)) { *mtu_min = member_mtu_min; // min MTU needs to be higher } if ((mtu_max != NULL) && (*mtu_max > member_mtu_max)) { *mtu_max = member_mtu_max; // max MTU needs to be lower } } } } } }
if (mtu_min != NULL) {#if IP_MSS > IPV6_MMTU if (*mtu_min < IP_MSS) { /* bump up the minimum MTU */ *mtu_min = IP_MSS/*576*/; }#else // IP_MSS > IPV6_MMTU if (*mtu_min < IPV6_MMTU) { /* bump up the minimum MTU */ *mtu_min = IPV6_MMTU; }#endif // IP_MSS > IPV6_MMTU
if ((mtu_cur != NULL) && (*mtu_min > *mtu_cur)) { /* min must be <= cur */ *mtu_min = *mtu_cur; }
if ((mtu_max != NULL) && (*mtu_min > *mtu_max)) { /* min must be <= max */ *mtu_min = *mtu_max; } } }
ok = TRUE;
done :
(void)close(sock); return ok;}
BooleanSCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface, CFStringRef subtype, CFArrayRef options){ CFDictionaryRef configuration; CFMutableDictionaryRef newConfiguration = NULL; Boolean ok = FALSE;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
configuration = SCNetworkInterfaceGetConfiguration(interface); if (configuration == NULL) { newConfiguration = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } else { newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); }
if (subtype != NULL) { CFArrayRef available = NULL; CFArrayRef config_options = options; CFArrayRef subtypes = NULL; CFArrayRef subtype_options = NULL;
if (options == NULL) { config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); }
if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) { SC_log(LOG_INFO, "media type / options not available"); goto checked; }
if (available == NULL) { _SCErrorSet(kSCStatusInvalidArgument); goto checked; }
subtypes = SCNetworkInterfaceCopyMediaSubTypes(available); if ((subtypes == NULL) || !CFArrayContainsValue(subtypes, CFRangeMake(0, CFArrayGetCount(subtypes)), subtype)) { SC_log(LOG_INFO, "media type not valid"); _SCErrorSet(kSCStatusInvalidArgument); goto checked; }
subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype); if ((subtype_options == NULL) || !CFArrayContainsValue(subtype_options, CFRangeMake(0, CFArrayGetCount(subtype_options)), config_options)) { SC_log(LOG_INFO, "media options not valid for \"%@\"", subtype); _SCErrorSet(kSCStatusInvalidArgument); goto checked; }
CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaSubType, subtype); CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaOptions, (options != NULL) ? options : 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) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaSubType); CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMediaOptions); if (CFDictionaryGetCount(newConfiguration) == 0) { CFRelease(newConfiguration); newConfiguration = NULL; } ok = TRUE; } else { SC_log(LOG_INFO, "media type must be specified with options"); _SCErrorSet(kSCStatusInvalidArgument); }
if (ok) { ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration); }
if (newConfiguration != NULL) CFRelease(newConfiguration); return ok;}
BooleanSCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface, int mtu){ CFDictionaryRef configuration; int mtu_max; int mtu_min; CFMutableDictionaryRef newConfiguration = NULL; Boolean ok = FALSE;
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) { SC_log(LOG_INFO, "MTU bounds not available"); return FALSE; }
configuration = SCNetworkInterfaceGetConfiguration(interface); if (configuration == NULL) { newConfiguration = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } else { newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); }
if ((mtu >= mtu_min) && (mtu <= mtu_max)) { CFNumberRef num;
num = CFNumberCreate(NULL, kCFNumberIntType, &mtu); CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMTU, num); CFRelease(num); ok = TRUE; } else if (mtu == 0) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetEthernetMTU); if (CFDictionaryGetCount(newConfiguration) == 0) { CFRelease(newConfiguration); newConfiguration = NULL; } ok = TRUE; } else { SC_log(LOG_INFO, "MTU out of range"); _SCErrorSet(kSCStatusInvalidArgument); }
if (ok) { ok = SCNetworkInterfaceSetConfiguration(interface, newConfiguration); }
if (newConfiguration != NULL) CFRelease(newConfiguration); return ok;}