#import <Foundation/Foundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IOEthernetController.h>
static NSDictionary* GetMACAddresses( io_iterator_t netIterator );
static kern_return_t FindNetworkInterfaces( io_iterator_t *services );
static NSString* bytesToHexString( NSData* data );
int main (int argc, const char * argv[]) {
io_iterator_t intfIterator;
kern_return_t kernResult = KERN_FAILURE;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Detecting Network Interfaces...");
kernResult = FindNetworkInterfaces( &intfIterator );
if( KERN_SUCCESS != kernResult ) {
printf( "findNetworkInterfaces failed\n" );
} else {
NSLog( @"Found one of more valid interfaces. Extracting MAC addresses..." );
NSDictionary* intfDictionary = GetMACAddresses( intfIterator );
for( id key in intfDictionary ) {
NSLog( @" %@ => %@", key, [intfDictionary objectForKey:key] );
}
IOObjectRelease( intfIterator );
}
[pool drain];
return 0;
}
/* Search through each of the Network interfaces identified
* in the netIterator and pull out the MAC address and the BSD
* name of the interface. Then convert the raw MAC address into
* a readable string and return an NSDictionary with a mapping of
* BSD Name (NSString*) => MAC Address (NSString*) for each interface
*/
static NSDictionary* GetMACAddresses( io_iterator_t netIterator ) {
NSMutableDictionary* etherDictionary = nil;
kern_return_t kernResult = KERN_FAILURE;
io_object_t interfaceService;
io_object_t controllerService;
while( interfaceService = IOIteratorNext( netIterator ) ) {
CFTypeRef MACAddrAsCFData = NULL;
CFTypeRef BSDNameAsCFString = NULL;
kernResult = IORegistryEntryGetParentEntry( interfaceService,
kIOServicePlane,
&controllerService );
if( KERN_SUCCESS != kernResult ) {
printf( "IORegistryEntryGetParentEntry failed with 0x%08x\n", kernResult );
} else {
MACAddrAsCFData = IORegistryEntryCreateCFProperty( controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0 );
BSDNameAsCFString = IORegistryEntryCreateCFProperty( interfaceService,
CFSTR("BSD Name"),
kCFAllocatorDefault,
0 );
if( MACAddrAsCFData && BSDNameAsCFString ) {
if( nil == etherDictionary ) {
etherDictionary = [[NSMutableDictionary alloc] init];
}
[etherDictionary setObject:bytesToHexString((NSData*)MACAddrAsCFData)
forKey:(NSString*)BSDNameAsCFString];
}
if( nil != BSDNameAsCFString ) {
CFRelease( BSDNameAsCFString );
}
if( nil != MACAddrAsCFData ) {
CFRelease( MACAddrAsCFData );
}
}
}
return (nil == etherDictionary) ? nil : (NSDictionary*)[etherDictionary autorelease];
}
/* Search through the IOServicePlane and find any services that
* represent an IOEthernetInterface. If you wanted to find a
* MAC address for a specific interface you could replace the
* IOServiceMatching calls with IOBSDNameMatching
*/
static kern_return_t FindNetworkInterfaces( io_iterator_t *services ) {
CFMutableDictionaryRef matchClasses = NULL;
kern_return_t kernResult = KERN_FAILURE;
mach_port_t machPort;
kernResult = IOMasterPort( MACH_PORT_NULL, &machPort );
if( KERN_SUCCESS != kernResult ) {
printf( "IOMasterPort failed: %d\n", kernResult );
}
matchClasses = IOServiceMatching( kIOEthernetInterfaceClass );
if( NULL == matchClasses ) {
printf( "IOServiceMatching returned a NULL dictionary" );
}
kernResult = IOServiceGetMatchingServices( machPort, matchClasses, services );
if( KERN_SUCCESS != kernResult ) {
printf( "IOServiceGetMatchingServices failed: %d\n", kernResult );
}
return kernResult;
}
static NSString* bytesToHexString( NSData* data ) {
NSMutableString* result = [[NSMutableString alloc] initWithCapacity: [data length] << 1];
UInt8* mbytes = (UInt8*)[data bytes];
char hBytes[8] = {'\0'};
int i = 0;
for( ; i < [data length]; i++ ) {
snprintf( hBytes, 3, "%02X", mbytes[ i ] );
if( 0 == i ) {
[result appendFormat:@"%s", hBytes];
} else {
[result appendFormat:@":%s", hBytes];
}
}
return (NSString*)[result autorelease];
}