Пример #1
0
// This function is much inspired by record_device() and devstats() from
// http://opensource.apple.com/source/system_cmds/system_cmds-230/iostat.tproj/iostat.c
static void reportDrive(dynamic_accumulator_t *ioLoad, io_registry_entry_t drive) {
  io_registry_entry_t parent;
  CFStringRef name;
  kern_return_t status;
  
  // get drive's parent
  status = IORegistryEntryGetParentEntry(drive,
                                         kIOServicePlane, &parent);
  if (status != KERN_SUCCESS) {
    return;
  }
  if (!IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
    IOObjectRelease(parent);
    return;
  }

  // get drive properties
  CFDictionaryRef driveProperties;
  status = IORegistryEntryCreateCFProperties(drive,
                                             (CFMutableDictionaryRef *)&driveProperties,
                                             kCFAllocatorDefault,
                                             kNilOptions);
  if (status != KERN_SUCCESS) {
    return;
  }
  
  // get name from properties
  name = (CFStringRef)CFDictionaryGetValue(driveProperties,
                                           CFSTR(kIOBSDNameKey));
  char cname[100];
  CFStringGetCString(name, cname, sizeof(cname), CFStringGetSystemEncoding());
  CFRelease(driveProperties);
  
  // get parent properties
  CFDictionaryRef parentProperties;
  status = IORegistryEntryCreateCFProperties(parent,
                                             (CFMutableDictionaryRef *)&parentProperties,
                                             kCFAllocatorDefault,
                                             kNilOptions);
  IOObjectRelease(parent);
  if (status != KERN_SUCCESS) {
    CFRelease(driveProperties);
    return;
  }
  
  CFDictionaryRef statistics;
  statistics = (CFDictionaryRef)CFDictionaryGetValue(parentProperties,
                                                     CFSTR(kIOBlockStorageDriverStatisticsKey));
  if (!statistics) {
    CFRelease(parentProperties);
    return;
  }
  
  u_int64_t bytesRead = 0;
  u_int64_t bytesWritten = 0;
  CFNumberRef number;
  if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
                                                  CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
    CFNumberGetValue(number, kCFNumberSInt64Type, &bytesRead);
  }
  if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
                                                  CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
    CFNumberGetValue(number, kCFNumberSInt64Type, &bytesWritten);
  }

  CFRelease(parentProperties);
  
  dynamic_accumulator_report(ioLoad, cname, bytesRead, bytesWritten);
}
Пример #2
0
/*
 * Gets the device's product name.
 */
static int
HIDGetDeviceProduct(io_service_t dev, char *name)
{
    CFMutableDictionaryRef hidProperties, usbProperties;
    io_registry_entry_t parent1, parent2;
    kern_return_t ret;

    hidProperties = usbProperties = 0;

    ret = IORegistryEntryCreateCFProperties(dev, &hidProperties,
                                            kCFAllocatorDefault, kNilOptions);
    if ((ret != KERN_SUCCESS) || !hidProperties) {
        SDL_SetError("Haptic: Unable to create CFProperties.");
        return -1;
    }

    /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
     * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
     */
    if ((KERN_SUCCESS ==
         IORegistryEntryGetParentEntry(dev, kIOServicePlane, &parent1))
        && (KERN_SUCCESS ==
            IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2))
        && (KERN_SUCCESS ==
            IORegistryEntryCreateCFProperties(parent2, &usbProperties,
                                              kCFAllocatorDefault,
                                              kNilOptions))) {
        if (usbProperties) {
            CFTypeRef refCF = 0;
            /* get device info
             * try hid dictionary first, if fail then go to usb dictionary
             */


            /* Get product name */
            refCF =
                CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey));
            if (!refCF)
                refCF =
                    CFDictionaryGetValue(usbProperties,
                                         CFSTR("USB Product Name"));
            if (refCF) {
                if (!CFStringGetCString(refCF, name, 256,
                                        CFStringGetSystemEncoding())) {
                    SDL_SetError
                        ("Haptic: CFStringGetCString error retrieving pDevice->product.");
                    return -1;
                }
            }

            CFRelease(usbProperties);
        } else {
            SDL_SetError
                ("Haptic: IORegistryEntryCreateCFProperties failed to create usbProperties.");
            return -1;
        }

        /* Release stuff. */
        if (kIOReturnSuccess != IOObjectRelease(parent2)) {
            SDL_SetError("Haptic: IOObjectRelease error with parent2.");
        }
        if (kIOReturnSuccess != IOObjectRelease(parent1)) {
            SDL_SetError("Haptic: IOObjectRelease error with parent1.");
        }
    } else {
        SDL_SetError("Haptic: Error getting registry entries.");
        return -1;
    }

    return 0;
}
Пример #3
0
static void HIDGetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, recDevice *pDevice)
{
	CFMutableDictionaryRef usbProperties = 0;
	io_registry_entry_t parent1, parent2;
	
	/* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
	 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
	 */
	if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) &&
		(KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) &&
		(KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions)))
	{
		if (usbProperties)
		{
			CFTypeRef refCF = 0;
			/* get device info
			 * try hid dictionary first, if fail then go to usb dictionary
			 */
			
			
			/* get product name */
			refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey));
			if (!refCF)
				refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name"));
			if (refCF)
			{
				if (!CFStringGetCString (refCF, pDevice->product, 256, CFStringGetSystemEncoding ()))
					SDL_SetError ("CFStringGetCString error retrieving pDevice->product.");
			}
			
			/* get usage page and usage */
			refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey));
			if (refCF)
			{
				if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage))
					SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage.");
				refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey));
				if (refCF)
					if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage))
						SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage.");
			}

			if (NULL == refCF) /* get top level element HID usage page or usage */
			{
				/* use top level element instead */
				CFTypeRef refCFTopElement = 0;
				refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey));
				{
					/* refCFTopElement points to an array of element dictionaries */
					CFRange range = {0, CFArrayGetCount (refCFTopElement)};
					CFArrayApplyFunction (refCFTopElement, range, HIDTopLevelElementHandler, pDevice);
				}
			}

			CFRelease (usbProperties);
		}
		else
			SDL_SetError ("IORegistryEntryCreateCFProperties failed to create usbProperties.");

		if (kIOReturnSuccess != IOObjectRelease (parent2))
			SDL_SetError ("IOObjectRelease error with parent2.");
		if (kIOReturnSuccess != IOObjectRelease (parent1))
			SDL_SetError ("IOObjectRelease error with parent1.");
	}
}
Пример #4
0
static void
HIDGetDeviceInfo(io_object_t hidDevice, CFMutableDictionaryRef hidProperties,
                 recDevice * pDevice)
{
    CFMutableDictionaryRef usbProperties = 0;
    io_registry_entry_t parent1, parent2;

    /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
     * get dictionary for USB properties: step up two levels and get CF dictionary for USB properties
     */
    if ((KERN_SUCCESS == IORegistryEntryGetParentEntry(hidDevice, kIOServicePlane, &parent1))
            && (KERN_SUCCESS == IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2))
            && (KERN_SUCCESS == IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) {
        if (usbProperties) {
            CFTypeRef refCF = 0;
            /* get device info
             * try hid dictionary first, if fail then go to usb dictionary
             */

            /* get product name */
            refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey));
            if (!refCF) {
                refCF = CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name"));
            }
            if (refCF) {
                if (!CFStringGetCString(refCF, pDevice->product, 256, CFStringGetSystemEncoding())) {
                    SDL_SetError("CFStringGetCString error retrieving pDevice->product.");
                }
            }

            /* get usage page and usage */
            refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey));
            if (refCF) {
                if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage)) {
                    SDL_SetError("CFNumberGetValue error retrieving pDevice->usagePage.");
                }

                refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey));
                if (refCF) {
                    if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage)) {
                        SDL_SetError("CFNumberGetValue error retrieving pDevice->usage.");
                    }
                }
            }

            refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDVendorIDKey));
            if (refCF) {
                if (!CFNumberGetValue(refCF, kCFNumberLongType, &pDevice->guid.data[0])) {
                    SDL_SetError("CFNumberGetValue error retrieving pDevice->guid[0]");
                }
            }

            refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductIDKey));
            if (refCF) {
                if (!CFNumberGetValue(refCF, kCFNumberLongType, &pDevice->guid.data[8])) {
                    SDL_SetError("CFNumberGetValue error retrieving pDevice->guid[8]");
                }
            }

            /* Check to make sure we have a vendor and product ID
               If we don't, use the same algorithm as the Linux code for Bluetooth devices */
            {
                Uint32 *guid32 = (Uint32*)pDevice->guid.data;
                if (!guid32[0] && !guid32[1]) {
                    const Uint16 BUS_BLUETOOTH = 0x05;
                    Uint16 *guid16 = (Uint16 *)guid32;
                    *guid16++ = BUS_BLUETOOTH;
                    *guid16++ = 0;
                    SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4);
                }
            }

            /* If we don't have a vendor and product ID this is probably a Bluetooth device */

            if (NULL == refCF) {    /* get top level element HID usage page or usage */
                /* use top level element instead */
                CFTypeRef refCFTopElement = 0;
                refCFTopElement = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDElementKey));
                {
                    /* refCFTopElement points to an array of element dictionaries */
                    CFRange range = { 0, CFArrayGetCount(refCFTopElement) };
                    CFArrayApplyFunction(refCFTopElement, range, HIDTopLevelElementHandler, pDevice);
                }
            }

            CFRelease(usbProperties);
        } else {
            SDL_SetError("IORegistryEntryCreateCFProperties failed to create usbProperties.");
        }

        if (kIOReturnSuccess != IOObjectRelease(parent2)) {
            SDL_SetError("IOObjectRelease error with parent2");
        }
        if (kIOReturnSuccess != IOObjectRelease(parent1)) {
            SDL_SetError("IOObjectRelease error with parent1");
        }
    }
}
Пример #5
0
RString ArchHooks_MacOSX::GetMachineId() const
{
	RString ret;
	CFMutableDictionaryRef dict = IOServiceMatching( "IOPlatformExpertDevice" );
	CFMutableDictionaryRef property;
	io_service_t service;

	if( dict )
	{
		// This consumes the reference.
		service = IOServiceGetMatchingService( kIOMasterPortDefault, dict );

		if( service )
		{
			CFTypeRef serial;
			CFStringRef key = CFSTR( "IOPlatformSerialNumber" ); // kIOPlatformSerialNumberKey

			serial = IORegistryEntryCreateCFProperty( service, key, kCFAllocatorDefault, 0 );

			if( serial )
			{
				const char *str = CFStringGetCStringPtr( (CFStringRef)serial, CFStringGetSystemEncoding() );
				ret = str? str:"";
				CFRelease( serial );
			}
			IOObjectRelease( service );
		}
	}

	dict = IOServiceMatching( kIOEthernetInterfaceClass );

	if( !dict )
		return ret;

	property = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
					      &kCFTypeDictionaryValueCallBacks );

	if( !property )
	{
		CFRelease( dict );
		return ret;
	}

	CFDictionarySetValue( property, CFSTR(kIOPrimaryInterface), kCFBooleanTrue );
	CFDictionarySetValue( dict, CFSTR(kIOPropertyMatchKey), property );
	CFRelease( property );

	io_iterator_t iter;

	if( IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iter) != KERN_SUCCESS )
		return ret;
	while( (service = IOIteratorNext(iter)) )
	{
		CFTypeRef data;
		io_object_t controller;

		if( IORegistryEntryGetParentEntry(service, kIOServicePlane, &controller) != KERN_SUCCESS )
		{
			IOObjectRelease( service );
			continue;
		}

		data = IORegistryEntryCreateCFProperty( controller, CFSTR(kIOMACAddress),
							kCFAllocatorDefault, 0 );
		if( data )
		{
			const uint8_t *p = CFDataGetBytePtr( (CFDataRef)data );
			
			ret += ssprintf( "-%02x:%02x:%02x:%02x:%02x:%02x",
					 p[0], p[1], p[2], p[3], p[4], p[5] );
			CFRelease( data );
		}
		IOObjectRelease( controller );
		IOObjectRelease( service );
	}
	IOObjectRelease( iter );
	return ret;
}
Пример #6
0
bool QextSerialEnumeratorPrivate::getServiceDetailsOSX(io_object_t service, QextPortInfo *portInfo)
{
    bool retval = true;
    CFTypeRef bsdPathAsCFString = NULL;
    CFTypeRef productNameAsCFString = NULL;
    CFTypeRef vendorIdAsCFNumber = NULL;
    CFTypeRef productIdAsCFNumber = NULL;
    // check the name of the modem's callout device
    bsdPathAsCFString = IORegistryEntryCreateCFProperty(service, CFSTR(kIOCalloutDeviceKey),
                                                        kCFAllocatorDefault, 0);

    // wander up the hierarchy until we find the level that can give us the
    // vendor/product IDs and the product name, if available
    io_registry_entry_t parent;
    kern_return_t kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
    while (kernResult == KERN_SUCCESS && !vendorIdAsCFNumber && !productIdAsCFNumber) {
        if (!productNameAsCFString)
            productNameAsCFString = IORegistryEntrySearchCFProperty(parent,
                                                                    kIOServicePlane,
                                                                    CFSTR("Product Name"),
                                                                    kCFAllocatorDefault, 0);
        vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
                                                             kIOServicePlane,
                                                             CFSTR(kUSBVendorID),
                                                             kCFAllocatorDefault, 0);
        productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
                                                              kIOServicePlane,
                                                              CFSTR(kUSBProductID),
                                                              kCFAllocatorDefault, 0);
        io_registry_entry_t oldparent = parent;
        kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent);
        IOObjectRelease(oldparent);
    }

    io_string_t ioPathName;
    IORegistryEntryGetPath(service, kIOServicePlane, ioPathName);
    portInfo->physName = ioPathName;

    if (bsdPathAsCFString) {
        char path[MAXPATHLEN];
        if (CFStringGetCString((CFStringRef)bsdPathAsCFString, path,
                               PATH_MAX, kCFStringEncodingUTF8))
            portInfo->portName = path;
        CFRelease(bsdPathAsCFString);
    }

    if (productNameAsCFString) {
        char productName[MAXPATHLEN];
        if (CFStringGetCString((CFStringRef)productNameAsCFString, productName,
                               PATH_MAX, kCFStringEncodingUTF8))
            portInfo->friendName = productName;
        CFRelease(productNameAsCFString);
    }

    if (vendorIdAsCFNumber) {
        SInt32 vID;
        if (CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberSInt32Type, &vID))
            portInfo->vendorID = vID;
        CFRelease(vendorIdAsCFNumber);
    }

    if (productIdAsCFNumber) {
        SInt32 pID;
        if (CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberSInt32Type, &pID))
            portInfo->productID = pID;
        CFRelease(productIdAsCFNumber);
    }
    IOObjectRelease(service);
    return retval;
}
/**
 * Get the MAC address of the first logical IP-enabled network interface
 *
 * @param out the output character array
 * @return CPL_OK on success or an error code
 */
cpl_return_t
cpl_platform_get_mac_address(cpl_mac_address_t* out)
{

#ifdef __unix__

	// From: http://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program

	ifreq ifr;
	ifconf ifc;
	char buf[1024];
	int success = 0;

	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if (sock == -1) return CPL_E_PLATFORM_ERROR;

	ifc.ifc_len = sizeof(buf);
	ifc.ifc_buf = buf;
	if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) return CPL_E_PLATFORM_ERROR;

	ifreq* it = ifc.ifc_req;
	const ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq));

	for (; it != end; ++it) {
		strcpy(ifr.ifr_name, it->ifr_name);
		if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
			if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
				if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
					success = 1;
					break;
				}
			}
		}
		else { /* ignore error */ }
	}

	if (success && out) {
		memcpy(out, ifr.ifr_hwaddr.sa_data, 6);
	}

	if (!success) return CPL_E_NOT_FOUND;

#elif defined(__APPLE__)

	/*
	 * Adapted from GetMACAddress.c:
	 *   http://opensource.apple.com/source/DirectoryService
	 *            /DirectoryService-621/CoreFramework/Private/GetMACAddress.c
	 *
	 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
	 * 
	 * 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.
	 */

	kern_return_t kernResult = KERN_FAILURE; 
	mach_port_t masterPort = MACH_PORT_NULL;
	CFMutableDictionaryRef classesToMatch = NULL;
	io_object_t intfService = MACH_PORT_NULL;
	io_object_t controllerService = MACH_PORT_NULL;
	io_iterator_t intfIterator = MACH_PORT_NULL;
	unsigned char macAddress[kIOEthernetAddressSize];
	io_iterator_t *matchingServices = &intfIterator;
	UInt8 *MACAddress = macAddress;

	// Create an iterator with Primary Ethernet interface
	kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
	if (kernResult != KERN_SUCCESS) return CPL_E_PLATFORM_ERROR;

	// Ethernet interfaces are instances of class kIOEthernetInterfaceClass
	classesToMatch = IOServiceMatching(kIOEthernetInterfaceClass);
	if (classesToMatch != NULL) {

		CFMutableDictionaryRef propertyMatch;
		propertyMatch = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
				&kCFTypeDictionaryKeyCallBacks,
				&kCFTypeDictionaryValueCallBacks);

		CFDictionarySetValue(propertyMatch,
				CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
		CFDictionarySetValue(classesToMatch,
				CFSTR(kIOPropertyMatchKey), propertyMatch);

		CFRelease(propertyMatch);

		kernResult = IOServiceGetMatchingServices(masterPort,
				classesToMatch, matchingServices);    
	}


	// Given an iterator across a set of Ethernet interfaces, return the
	// MAC address of the first one.

	intfService = IOIteratorNext(intfIterator);
	if (intfService == MACH_PORT_NULL) {
			IOObjectRelease(intfIterator);
			return CPL_E_PLATFORM_ERROR;
	}

	CFDataRef MACAddressAsCFData = NULL;        
	kernResult = IORegistryEntryGetParentEntry(intfService,
			kIOServicePlane,
			&controllerService);

	if (kernResult != KERN_SUCCESS || controllerService == MACH_PORT_NULL) {
		IOObjectRelease(intfService);
		IOObjectRelease(intfIterator);
		return CPL_E_PLATFORM_ERROR;
	}

	MACAddressAsCFData = (CFDataRef) IORegistryEntryCreateCFProperty(
			controllerService,
			CFSTR(kIOMACAddress),
			kCFAllocatorDefault,
			0);

	if (MACAddressAsCFData != NULL) {
		CFDataGetBytes(MACAddressAsCFData,
				CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
		CFRelease(MACAddressAsCFData);
	}
	else {
		IOObjectRelease(controllerService);
		IOObjectRelease(intfService);
		IOObjectRelease(intfIterator);
		return CPL_E_NOT_FOUND;
	}

	IOObjectRelease(controllerService);
	IOObjectRelease(intfService);
	IOObjectRelease(intfIterator);

	if (out) memcpy(out, macAddress, 6);
	

#elif defined(_WINDOWS)

	PIP_ADAPTER_ADDRESSES AdapterAddresses;
	ULONG family = AF_UNSPEC;
	ULONG flags = 0;
	ULONG outBufLen = 0;
	bool success = false;

	DWORD dwRetVal = GetAdaptersAddresses(family, flags, NULL, NULL, &outBufLen);
	if (dwRetVal == ERROR_NO_DATA) return CPL_E_NOT_FOUND;
	if (dwRetVal == 0 && outBufLen == 0) return CPL_E_NOT_FOUND;
	if (dwRetVal != ERROR_BUFFER_OVERFLOW) return CPL_E_PLATFORM_ERROR;

	AdapterAddresses = (IP_ADAPTER_ADDRESSES*)
		malloc(sizeof(IP_ADAPTER_ADDRESSES) * outBufLen);
	if (AdapterAddresses == NULL) return CPL_E_INSUFFICIENT_RESOURCES;

	dwRetVal = GetAdaptersAddresses(family, flags, NULL, AdapterAddresses,
		&outBufLen);
	if (dwRetVal != 0) { free(AdapterAddresses); return CPL_E_PLATFORM_ERROR; }

	for (PIP_ADAPTER_ADDRESSES p = AdapterAddresses; p != NULL; p = p->Next) {
		if (p->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
		if (p->PhysicalAddressLength != 6 /* Ethernet */) continue;

		success = true;
		if (out) memcpy(out, p->PhysicalAddress, 6);
		break;
	}

	free(AdapterAddresses);

	if (!success) return CPL_E_NOT_FOUND;

#else
#error "Not implemented for this platform"
#endif

	return CPL_OK;
}