iokit.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
/* $Id$ */
/** @file
* Main - Darwin IOKit Routines.
*
* Because IOKit makes use of COM like interfaces, it does not mix very
* simpler C interface.
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_MAIN
#ifdef STANDALONE_TESTCASE
# define VBOX_WITH_USB
#endif
#include <IOKit/IOKitLib.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <mach/mach_error.h>
#ifdef VBOX_WITH_USB
# include <IOKit/IOCFPlugIn.h>
#endif
#ifdef STANDALONE_TESTCASE
# include <iprt/initterm.h>
#endif
#include "iokit.h"
/* A small hack... */
#ifdef STANDALONE_TESTCASE
# define DarwinFreeUSBDeviceFromIOKit(a) do { } while (0)
#endif
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** An attempt at catching reference leaks. */
#define MY_CHECK_CREFS(cRefs) do { AssertMsg(cRefs < 25, ("%ld\n", cRefs)); NOREF(cRefs); } while (0)
/** Contains the pid of the current client. If 0, the kernel is the current client. */
#define VBOXUSB_CLIENT_KEY "VBoxUSB-Client"
/** Contains the pid of the filter owner (i.e. the VBoxSVC pid). */
#define VBOXUSB_OWNER_KEY "VBoxUSB-Owner"
/** The VBoxUSBDevice class name. */
#define VBOXUSBDEVICE_CLASS_NAME "org_virtualbox_VBoxUSBDevice"
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The IO Master Port. */
/**
* Lazily opens the master port.
*
* @returns true if the port is open, false on failure (very unlikely).
*/
static bool darwinOpenMasterPort(void)
{
if (!g_MasterPort)
{
}
return true;
}
/**
* Checks whether the value exists.
*
* @returns true / false accordingly.
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
*/
{
}
/**
* Gets a boolean value.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pf Where to store the key value.
*/
{
if ( BoolRef
{
return true;
}
*pf = false;
return false;
}
/**
* Gets an unsigned 8-bit integer value.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pu8 Where to store the key value.
*/
{
if (ValRef)
{
return true;
}
*pu8 = 0;
return false;
}
/**
* Gets an unsigned 16-bit integer value.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pu16 Where to store the key value.
*/
{
if (ValRef)
{
return true;
}
*pu16 = 0;
return false;
}
/**
* Gets an unsigned 32-bit integer value.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pu32 Where to store the key value.
*/
{
if (ValRef)
{
return true;
}
*pu32 = 0;
return false;
}
/**
* Gets an unsigned 64-bit integer value.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pu64 Where to store the key value.
*/
{
if (ValRef)
{
return true;
}
*pu64 = 0;
return false;
}
/**
* Gets a RTPROCESS value.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pProcess Where to store the key value.
*/
static bool darwinDictGetProcess(CFMutableDictionaryRef DictRef, CFStringRef KeyStrRef, PRTPROCESS pProcess)
{
switch (sizeof(*pProcess))
{
default:
}
}
/**
* Gets string value, converted to UTF-8 and put in user buffer.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param psz The string buffer. On failure this will be an empty string ("").
* @param cch The size of the buffer.
*/
static bool darwinDictGetString(CFDictionaryRef DictRef, CFStringRef KeyStrRef, char *psz, size_t cch)
{
if (ValRef)
{
return true;
}
*psz = '\0';
return false;
}
/**
* Gets string value, converted to UTF-8 and put in a IPRT string buffer.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param ppsz Where to store the key value. Free with RTStrFree. Set to NULL on failure.
*/
{
char szBuf[512];
{
if (*ppsz)
return true;
}
return false;
}
/**
* Gets a byte string (data) of a specific size.
*
* @param DictRef The dictionary.
* @param KeyStrRef The key name.
* @param pvBuf The buffer to store the bytes in.
* @param cbBuf The size of the buffer. This must exactly match the data size.
*/
static bool darwinDictGetData(CFDictionaryRef DictRef, CFStringRef KeyStrRef, void *pvBuf, size_t cbBuf)
{
if (ValRef)
{
{
return true;
}
}
return false;
}
# define DARWIN_IOKIT_LOG(a) Log(a)
# define DARWIN_IOKIT_LOG_FLUSH() do {} while (0)
# define DARWIN_IOKIT_DUMP_OBJ(o) do {} while (0)
#else
# if defined(STANDALONE_TESTCASE)
# define DARWIN_IOKIT_LOG(a) RTPrintf a
# else
# define DARWIN_IOKIT_LOG(a) RTLogPrintf a
# endif
# define DARWIN_IOKIT_DUMP_OBJ(o) darwinDumpObj(o)
/**
* Callback for dumping a dictionary key.
*
* @param pvKey The key name.
* @param pvValue The key value
* @param pvUser The recursion depth.
*/
{
/* display the key name. */
/* display the value type */
/* display the value */
if (Type == CFDictionaryGetTypeID())
{
DARWIN_IOKIT_LOG(("dictionary] =\n"
CFDictionaryApplyFunction((CFDictionaryRef)pvValue, darwinDumpDictCallback, (void *)((uintptr_t)pvUser + 4));
}
else if (Type == CFBooleanGetTypeID())
else if (Type == CFNumberGetTypeID())
{
union
{
char ch;
short s;
int i;
long l;
long long ll;
float rf;
double rd;
} u;
memset(&u, 0, sizeof(u));
{
{
case kCFNumberSInt16Type: DARWIN_IOKIT_LOG(("SInt16] = %RI16 (%#RX16)\n", NumType, u.s16, u.s16)); break;
case kCFNumberSInt32Type: DARWIN_IOKIT_LOG(("SInt32] = %RI32 (%#RX32)\n", NumType, u.s32, u.s32)); break;
case kCFNumberSInt64Type: DARWIN_IOKIT_LOG(("SInt64] = %RI64 (%#RX64)\n", NumType, u.s64, u.s64)); break;
case kCFNumberLongLongType: DARWIN_IOKIT_LOG(("long long] = %lld (%#llx)\n", NumType, u.ll, u.ll)); break;
case kCFNumberCFIndexType: DARWIN_IOKIT_LOG(("CFIndex] = %lld (%#llx)\n", NumType, (long long)u.iCF, (long long)u.iCF)); break;
break;
}
}
else
DARWIN_IOKIT_LOG(("number] = CFNumberGetValue failed\n"));
}
else if (Type == CFBooleanGetTypeID())
else if (Type == CFStringGetTypeID())
{
DARWIN_IOKIT_LOG(("string] = "));
}
else if (Type == CFDataGetTypeID())
{
if (!cb)
DARWIN_IOKIT_LOG((" \n"));
else if (cb <= 32)
else
}
else
}
/**
* Dumps a dictionary to the log.
*
* @param DictRef The dictionary to dump.
*/
{
}
/**
* Dumps an I/O kit registry object and all it children.
* @param Object The object to dump.
* @param cIndents The number of indents to use.
*/
{
static io_string_t s_szPath;
if (krc != KERN_SUCCESS)
if (krc == KERN_SUCCESS)
{
}
/*
* Children.
*/
if (krc == KERN_SUCCESS)
{
{
}
}
else
}
/**
* Dumps an I/O kit registry object and all it children.
* @param Object The object to dump.
*/
{
darwinDumpObjInt(Object, 0);
}
#endif /* helpers for dumping registry dictionaries */
#ifdef VBOX_WITH_USB
/**
* Notification data created by DarwinSubscribeUSBNotifications, used by
* the callbacks and finally freed by DarwinUnsubscribeUSBNotifications.
*/
typedef struct DARWINUSBNOTIFY
{
/** The notification port.
* It's shared between the notification callbacks. */
/** The run loop source for NotifyPort. */
/** The attach notification iterator. */
/** The 2nd attach notification iterator. */
/** The detach notificaiton iterator. */
/**
* Run thru an interrator.
*
* The docs says this is necessary to start getting notifications,
* so this function is called in the callbacks and right after
* registering the notification.
*
* @param pIterator The iterator reference.
*/
{
{
}
}
/**
* Callback for the 1st attach notification.
*
* @param pvNotify Our data.
* @param NotifyIterator The notification iterator.
*/
{
DARWIN_IOKIT_LOG(("USB Attach Notification1\n"));
}
/**
* Callback for the 2nd attach notification.
*
* @param pvNotify Our data.
* @param NotifyIterator The notification iterator.
*/
{
DARWIN_IOKIT_LOG(("USB Attach Notification2\n"));
}
/**
* Callback for the detach notifications.
*
* @param pvNotify Our data.
* @param NotifyIterator The notification iterator.
*/
{
DARWIN_IOKIT_LOG(("USB Detach Notification\n"));
}
/**
* Subscribes the run loop to USB notification events relevant to
*
* The source mode for these events is defined as VBOX_IOKIT_MODE_STRING
* so that the caller can listen to events from this mode only and
* re-evalutate the list of attached devices whenever an event arrives.
*
* @returns opaque for passing to the unsubscribe function. If NULL
* something unexpectedly failed during subscription.
*/
void *DarwinSubscribeUSBNotifications(void)
{
/*
* Create the notification port, bake it into a runloop source which we
* then add to our run loop.
*/
if (pNotify->NotifyPort)
{
if (pNotify->NotifyRLSrc)
{
CFRetain(RunLoopRef); /* Workaround for crash when cleaning up the TLS / runloop((sub)mode). See #2807. */
/*
* Create the notifcation callbacks.
*/
if (rc == KERN_SUCCESS)
{
if (rc == KERN_SUCCESS)
{
{
return pNotify;
}
}
}
}
}
return NULL;
}
/**
* Unsubscribe the run loop from USB notification subscribed to
* by DarwinSubscribeUSBNotifications.
*
* @param pvOpaque The return value from DarwinSubscribeUSBNotifications.
*/
void DarwinUnsubscribeUSBNotifications(void *pvOpaque)
{
if (!pNotify)
return;
}
/**
* Decends recursivly into a IORegistry tree locating the first object of a given class.
*
* The search is performed depth first.
*
* @returns Object reference if found, NULL if not.
* @param Object The current tree root.
* @param pszClass The name of the class we're looking for.
* @param pszNameBuf A scratch buffer for query the class name in to avoid
* wasting 128 bytes on an io_name_t object for every recursion.
*/
static io_object_t darwinFindObjectByClass(io_object_t Object, const char *pszClass, io_name_t pszNameBuf)
{
if (krc != KERN_SUCCESS)
return NULL;
{
if ( krc == KERN_SUCCESS
break;
if (GrandChild)
{
Child = GrandChild;
break;
}
}
return Child;
}
/**
* Decends recursivly into IOUSBMassStorageClass tree to check whether
* the MSD is mounted or not.
*
* The current heuristic is to look for the IOMedia class.
*
* @returns true if mounted, false if not.
* @param MSDObj The IOUSBMassStorageClass object.
* @param pszNameBuf A scratch buffer for query the class name in to avoid
* wasting 128 bytes on an io_name_t object for every recursion.
*/
{
if (MediaObj)
{
/* more checks? */
return true;
}
return false;
}
/**
* Worker function for DarwinGetUSBDevices() that tries to figure out
* what state the device is in and set enmState.
*
* This is mostly a matter of distinguishing between devices that nobody
* uses, devices that can be seized and devices that cannot be grabbed.
*
* @param pCur The USB device data.
* @param USBDevice The USB device object.
* @param PropsRef The USB device properties.
*/
static void darwinDeterminUSBDeviceState(PUSBDEVICE pCur, io_object_t USBDevice, CFMutableDictionaryRef /* PropsRef */)
{
/*
* Iterate the interfaces (among the children of the IOUSBDevice object).
*/
if (krc != KERN_SUCCESS)
return;
bool fHaveOwner = false;
bool fHaveClient = false;
bool fUserClientOnly = true;
bool fConfigured = false;
bool fInUse = false;
bool fSeizable = true;
{
if ( krc == KERN_SUCCESS
{
fConfigured = true;
/*
* Iterate the interface children looking for stuff other than
* IOUSBUserClientInit objects.
*/
if (krc == KERN_SUCCESS)
{
{
if ( krc == KERN_SUCCESS
{
fUserClientOnly = false;
{
/* Only permit capturing MSDs that aren't mounted, at least
until the GUI starts poping up warnings about data loss
and such when capturing a busy device. */
fSeizable = false;
}
/** @todo more? */)
{
/* For now, just assume that all HID devices are inaccessible
because of the greedy HID service. */
fSeizable = false;
fInUse = true;
}
else
fInUse = true;
}
}
}
}
/*
* Not an interface, could it be VBoxUSBDevice?
* If it is, get the owner and client properties.
*/
else if ( krc == KERN_SUCCESS
{
if (krc == KERN_SUCCESS)
{
}
}
}
/*
* Calc the status.
*/
if (fHaveOwner)
{
if (Owner == RTProcSelf())
else
}
else if (fUserClientOnly)
/** @todo how to detect other user client?!? - Look for IOUSBUserClient! */
else if (!fInUse)
else
}
/**
* Enumerate the USB devices returning a FIFO of them.
*
* @returns Pointer to the head.
* USBProxyService::freeDevice is expected to free each of the list elements.
*/
{
//DARWIN_IOKIT_LOG(("DarwinGetUSBDevices\n"));
/*
* Create a matching dictionary for searching for USB Devices in the IOKit.
*/
/*
* Perform the search and get a collection of USB Device back.
*/
/*
* Enumerate the USB Devices.
*/
unsigned i = 0;
{
/*
* Query the device properties from the registry.
*
* We could alternatively use the device and such, but that will be
* slower and we would have to resort to the registry for the three
* string anyway.
*/
kern_return_t krc = IORegistryEntryCreateCFProperties(USBDevice, &PropsRef, kCFAllocatorDefault, kNilOptions);
if (krc == KERN_SUCCESS)
{
bool fOk = false;
do /* loop for breaking out of on failure. */
{
/*
* Mandatory
*/
pCur->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE; /* just a default, we'll try harder in a bit. */
/* skip hubs */
break;
char szAddress[64];
: bSpeed == 0 ? USBDEVICESPEED_LOW
/*
* Optional.
* There are some nameless device in the iMac, apply names to them.
*/
if ( !pCur->pszManufacturer
if ( !pCur->pszProduct
#if 0 /* leave the remainder as zero for now. */
/*
* Create a plugin interface for the service and query its USB Device interface.
*/
if (rc == kIOReturnSuccess)
{
{
/** @todo enumerate configurations and interfaces if we actually need them. */
//IOReturn (*GetNumberOfConfigurations)(void *self, UInt8 *numConfig);
//IOReturn (*GetConfigurationDescriptorPtr)(void *self, UInt8 configIndex, IOUSBConfigurationDescriptorPtr *desc);
//IOReturn (*CreateInterfaceIterator)(void *self, IOUSBFindInterfaceRequest *req, io_iterator_t *iter);
}
}
#endif
/*
* Try determin the state.
*/
/*
* We're good. Link the device.
*/
if (pTail)
else
fOk = true;
} while (0);
/* cleanup on failure / skipped device. */
}
else
i++;
}
//DARWIN_IOKIT_LOG_FLUSH();
/*
* Some post processing. There are a couple of things we have to
* make 100% sure about, and that is that the (Apple) keyboard
* and mouse most likely to be in use by the user aren't available
* for capturing. If there is no Apple mouse or keyboard we'll
* take the first one from another vendor.
*/
/* As it turns out, the HID service will take all keyboards and mice
and we're not currently able to seize them. */
{
/*
* we don't have interface info yet so that might be a bit tricky.
*/
if ( ( !pKeyboard
&& pCur->pszProduct
else if ( ( !pMouse
&& pCur->pszProduct
)
}
{
/** @todo examin interfaces */
}
if (pKeyboard)
if (pMouse)
return pHead;
}
/**
* Triggers re-enumeration of a device.
*
* @returns VBox status code.
* @param pCur The USBDEVICE structure for the device.
*/
{
int vrc;
/*
* This code is a short version of the Open method in USBProxyDevice-darwin.cpp stuff.
* Fixes made to this code probably applies there too!
*/
uint64_t u64SessionId = 0;
uint32_t u32LocationId = 0;
const char *psz = pszAddress;
do
{
switch (chValue)
{
case 'l':
break;
case 's':
break;
case 'p':
case 'v':
{
#if 0 /* Guess what, this doesn't 'ing work either! */
CFDictionarySetValue(RefMatchingDict, chValue == 'p' ? CFSTR(kUSBProductID) : CFSTR(kUSBVendorID), Num);
#endif
break;
}
default:
}
if (*psz == ';')
psz++;
} while (*psz);
unsigned cMatches = 0;
{
cMatches++;
kern_return_t krc = IORegistryEntryCreateCFProperties(USBDevice, &PropsRef, kCFAllocatorDefault, kNilOptions);
if (krc == KERN_SUCCESS)
{
if ( ( !u64SessionId
&& u64CurSessionId == u64SessionId))
&& ( !u32LocationId
&& u32CurLocationId == u32LocationId))
)
{
break;
}
}
}
USBDevices = NULL;
if (!USBDevice)
{
return VERR_VUSB_DEVICE_NAME_NOT_FOUND;
}
/*
* Create a plugin interface for the device and query its IOUSBDeviceInterface.
*/
if (irc == kIOReturnSuccess)
{
{
/*
* Try open the device for exclusive access.
*/
if (irc == kIOReturnExclusiveAccess)
{
RTThreadSleep(20);
}
if (irc == kIOReturnSuccess)
{
/*
* Re-enumerate the device and bail out.
*/
if (irc == kIOReturnSuccess)
vrc = VINF_SUCCESS;
else
{
LogRel(("USB: Failed to open device '%s', plug-in creation failed with irc=%#x.\n", pszAddress, irc));
}
}
else if (irc == kIOReturnExclusiveAccess)
{
}
else
{
}
}
else
{
}
}
else
{
LogRel(("USB: Failed to open device '%s', plug-in creation failed with irc=%#x.\n", pszAddress, irc));
}
return vrc;
}
#endif /* VBOX_WITH_USB */
/**
* Enumerate the DVD drives returning a FIFO of device name strings.
*
* @returns Pointer to the head.
* The caller is responsible for calling RTMemFree() on each of the nodes.
*/
PDARWINDVD DarwinGetDVDDrives(void)
{
/*
* Create a matching dictionary for searching for DVD services in the IOKit.
*
* [If I understand this correctly, plain CDROMs doesn't show up as
* IODVDServices. Too keep things simple, we will only support DVDs
* until somebody complains about it and we get hardware to test it on.
* (Unless I'm much mistaken, there aren't any (orignal) intel macs with
* plain cdroms.)]
*/
/*
* Perform the search and get a collection of DVD services.
*/
/*
* Enumerate the DVD services.
* (This enumeration must be identical to the one performed in DrvHostBase.cpp.)
*/
unsigned i = 0;
{
/*
* Get the properties we use to identify the DVD drive.
*
* While there is a (weird 12 byte) GUID, it isn't persistent
* accross boots. So, we have to use a combination of the
* vendor name and product name properties with an optional
* sequence number for identification.
*/
kern_return_t krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);
if (krc == KERN_SUCCESS)
{
/* Get the Device Characteristics dictionary. */
CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));
if (DevCharRef)
{
/* The vendor name. */
char szVendor[128];
if ( ValueRef
else
*pszVendor = '\0';
/* The product name. */
char szProduct[128];
char *pszProduct = &szProduct[0];
if ( ValueRef
else
*pszProduct = '\0';
/* Construct the name and check for duplicates. */
if (*pszVendor || *pszProduct)
{
if (*pszVendor && *pszProduct)
else
{
{
if (*pszVendor && *pszProduct)
else
break;
}
}
}
else
/* Create the device. */
if (pNew)
{
if (pTail)
else
}
}
}
else
i++;
}
return pHead;
}
/**
* Enumerate the ethernet capable network devices returning a FIFO of them.
*
* @returns Pointer to the head.
*/
{
/*
* Create a matching dictionary for searching for ethernet controller
* services in the IOKit.
*
* For some really stupid reason I don't get all the controllers if I look for
* objects that are instances of IOEthernetController or its decendants (only
* get the AirPort on my mac pro). But fortunately using IOEthernetInterface
* seems to work. Weird s**t!
*/
//CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOEthernetController"); - this doesn't work :-(
/*
* Perform the search and get a collection of ethernet controller services.
*/
/*
* Get a copy of the current network interfaces from the system configuration service.
* We'll use this for looking up the proper interface names.
*/
/*
* Get the current preferences and make a copy of the network services so we
* can look up the right interface names. The IfsRef is just for fallback.
*/
SCPreferencesRef PrefsRef = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("org.virtualbox.VBoxSVC"), NULL);
if (PrefsRef)
{
if (SetRef)
{
}
}
/*
* Enumerate the ethernet controller services.
*/
{
/*
* Dig up the parent, meaning the IOEthernetController.
*/
kern_return_t krc = IORegistryEntryGetParentEntry(EtherIfService, kIOServicePlane, &EtherNICService);
/*krc = IORegistryEntryGetChildEntry(EtherNICService, kIOServicePlane, &EtherIfService); */
if (krc == KERN_SUCCESS)
{
/*
* Get the properties we use to identify and name the Ethernet NIC.
* We need the both the IOEthernetController and it's IONetworkInterface child.
*/
krc = IORegistryEntryCreateCFProperties(EtherNICService, &PropsRef, kCFAllocatorDefault, kNilOptions);
if (krc == KERN_SUCCESS)
{
krc = IORegistryEntryCreateCFProperties(EtherIfService, &IfPropsRef, kCFAllocatorDefault, kNilOptions);
if (krc == KERN_SUCCESS)
{
/*
* Gather the required data.
* We'll create a UUID from the MAC address and the BSD name.
*/
char szTmp[256];
do
{
/* Check if airport (a bit heuristical - it's com.apple.driver.AirPortBrcm43xx here). */
bool fWireless;
/* Check if it's USB. */
/* Is it builtin? */
bool fBuiltin;
/* Is it the primary interface */
bool fPrimaryIf;
/* Get the MAC address. */
/* The BSD Name from the interface dictionary. */
/* Check if it's really wireless. */
fWireless = true;
else
/** @todo IOPacketFilters / IONetworkFilterGroup? */
/*
* Create the interface name.
*
* Note! The ConsoleImpl2.cpp code ASSUMES things about the name. It is also
* stored in the VM config files. (really bright idea)
*/
*psz++ = ':';
*psz++ = ' ';
bool fFound = false;
CFIndex i;
/* look it up among the current services */
for (i = 0; i < cServices; i++)
{
if (IfRef)
{
if ( BSDNameRef
{
if ( ServiceNameRef
{
fFound = true;
break;
}
}
}
}
/* Look it up in the interface list. */
if (!fFound)
for (i = 0; i < cIfs; i++)
{
if ( BSDNameRef
{
if ( DisplayNameRef
{
fFound = true;
break;
}
}
}
/* Generate a half plausible name if we for some silly reason didn't find the interface. */
if (!fFound)
/* If we did find it and it's wireless but without "AirPort" or "Wireless", fix it */
else if ( fWireless
/*
* Create the list entry.
*/
DARWIN_IOKIT_LOG(("Found: if=%s mac=%.6Rhxs fWireless=%RTbool fAirPort=%RTbool fBuiltin=%RTbool fPrimaryIf=%RTbool fUSB=%RTbool\n",
PDARWINETHERNIC pNew = (PDARWINETHERNIC)RTMemAlloc(RT_OFFSETOF(DARWINETHERNIC, szName[cchName + 1]));
if (pNew)
{
strncpy(pNew->szBSDName, szBSDName, sizeof(pNew->szBSDName)); /* the '\0' padding is intentional! */
/*
* Link it into the list, keep the list sorted by fPrimaryIf and the BSD name.
*/
if (pTail)
{
{
break;
}
if (pPrev)
{
/* tail or in list. */
}
else
{
/* head */
}
}
else
{
/* empty list */
}
}
} while (0);
}
}
}
else
}
if (ServicesRef)
if (IfsRef)
return pHead;
}
#ifdef STANDALONE_TESTCASE
/**
* This file can optionally be compiled into a testcase, this is the main function.
* To build:
* g++ -I ../../../../include -D IN_RING3 iokit.cpp ../../../../out/darwin.x86/debug/lib/RuntimeR3.a ../../../../out/darwin.x86/debug/lib/SUPR3.a ../../../../out/darwin.x86/debug/lib/RuntimeR3.a ../../../../out/darwin.x86/debug/lib/VBox-kStuff.a ../../../../out/darwin.x86/debug/lib/RuntimeR3.a -framework CoreFoundation -framework IOKit -framework SystemConfiguration -liconv -D STANDALONE_TESTCASE -o iokit -g && ./iokit
*/
{
RTR3Init();
if (1)
{
/*
* Network preferences.
*/
RTPrintf("Preferences: Network Services\n");
SCPreferencesRef PrefsRef = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("org.virtualbox.VBoxSVC"), NULL);
if (PrefsRef)
{
CFDictionaryRef NetworkServiceRef = (CFDictionaryRef)SCPreferencesGetValue(PrefsRef, kSCPrefNetworkServices);
}
}
if (1)
{
/*
* Network services interfaces in the current config.
*/
RTPrintf("Preferences: Network Service Interfaces\n");
SCPreferencesRef PrefsRef = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("org.virtualbox.VBoxSVC"), NULL);
if (PrefsRef)
{
if (SetRef)
{
{
char szServiceName[128] = {0};
CFStringGetCString(SCNetworkServiceGetName(ServiceRef), szServiceName, sizeof(szServiceName), kCFStringEncodingUTF8);
char szBSDName[16] = {0};
CFStringGetCString(SCNetworkInterfaceGetBSDName(IfRef), szBSDName, sizeof(szBSDName), kCFStringEncodingUTF8);
char szDisplayName[128] = {0};
CFStringGetCString(SCNetworkInterfaceGetLocalizedDisplayName(IfRef), szDisplayName, sizeof(szDisplayName), kCFStringEncodingUTF8);
RTPrintf(" #%u ServiceName=\"%s\" IfBSDName=\"%s\" IfDisplayName=\"%s\"\n",
}
}
}
}
if (1)
{
/*
* Network interfaces.
*/
RTPrintf("Preferences: Network Interfaces\n");
if (IfsRef)
{
{
char szBSDName[16] = {0};
CFStringGetCString(SCNetworkInterfaceGetBSDName(IfRef), szBSDName, sizeof(szBSDName), kCFStringEncodingUTF8);
char szDisplayName[128] = {0};
CFStringGetCString(SCNetworkInterfaceGetLocalizedDisplayName(IfRef), szDisplayName, sizeof(szDisplayName), kCFStringEncodingUTF8);
RTPrintf(" #%u BSDName=\"%s\" DisplayName=\"%s\"\n",
i, szBSDName, szDisplayName);
}
}
}
if (1)
{
/*
* Get and display the ethernet controllers.
*/
RTPrintf("Ethernet controllers:\n");
{
}
}
return 0;
}
#endif