Hello, I'm trying to get a list of all network devices (device audit for DLP system).
CFMutableDictionaryRef matchingDictionary = IOServiceMatching(kIONetworkControllerClass);
if (matchingDictionary == nullptr)
{
std::cerr << "IOServiceMatching() returned empty matching dictionary" << std::endl;
return 1;
}
io_iterator_t iter;
if (kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &iter);
kr != KERN_SUCCESS)
{
std::cerr << "IOServiceGetMatchingServices() failed" << std::endl;
return 1;
}
io_service_t networkController;
while ((networkController = IOIteratorNext(iter)) != IO_OBJECT_NULL)
{
std::cout << "network device: ";
if (CFDataRef cfIOMACAddress = (CFDataRef) IORegistryEntryCreateCFProperty(networkController, CFSTR(kIOMACAddress), kCFAllocatorDefault, kNilOptions);
cfIOMACAddress != nullptr)
{
std::vector<uint8_t> data(CFDataGetLength(cfIOMACAddress));
CFDataGetBytes(cfIOMACAddress, CFRangeMake(0, data.size()), data.data());
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short)data[0] << ":"
<< std::hex << std::setfill('0') << std::setw(2) << (short) data[1] << ":"
<< std::hex << std::setfill('0') << std::setw(2) << (short) data[2] << ":"
<< std::hex << std::setfill('0') << std::setw(2) << (short) data[3] << ":"
<< std::hex << std::setfill('0') << std::setw(2) << (short) data[4] << ":"
<< std::hex << std::setfill('0') << std::setw(2) << (short) data[5];
CFRelease(cfIOMACAddress);
}
std::cout << std::endl;
IOObjectRelease(networkController);
}
IOObjectRelease(iter);
The Wi-Fi controller shows up in I/O Registry Explorer, but IOServiceGetMatchingServices()
does not return any information about it.
Any way to retrieve Wi-Fi controller info in daemon code?
Thank you in advance!
Hi,
The Wi-Fi controller shows up in I/O Registry Explorer,
SO, the first thing to understand here is that IORegistryExplorer.app is basically a "public" app. It has no special entitlements* and uses no private API. It's not open source, but it's command line equivalent "ioreg" is, so you can see the code yourself if you're curious.
*Keep in mind that IORegistryExplorer.app is positively ancient at this point. For example, it's "About" dialog says "Copyright 2000 - 2013". It continues to work because this part of this system doesn't really change, not because it requires active maintenance.
The critical point here is that if you're not getting the response you're expecting, it's almost always because of what you're doing/asking, not because the information isn't there or can't be retrieved.
That leads to here:
but IOServiceGetMatchingServices() does not return any information about it.
More specifically, IOServiceGetMatchingServices is not returning the object you're expecting it to. The reason for that is actually documented, but easy to overlook:
"This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked)."
You can find the larger background to this in the section "Driver Matching and Loading" of IOKit Fundamentals, however, the short summary is that, conceptually, IOKit drivers can actually be grouped into two categories:
-
"Drivers", which match against some specific object (their IOProvider).
-
"Nubs", which call registerService expecting "something" to match against them.
The idea here is that "Nubs" are what define the interface between the different layers of the driver system (particularly between families) while the intermediate Drivers can then be implemented however the implementer wants. The "basic" concept is that you'd then have an alternating layer stack of:
...Nub-> Driver-> Nub-> Driver...
...but the system has always been "messier" than that. However, the key point here is that that IOServiceGetMatchingServices does NOT find "IOKit objects", it ONLY finds "Nubs" or, more specifically, "objects that called registerService".
The final detail to all of this (which isn't really documented) is probably DriverKit. I'm not sure of exactly which object you were targeting in the registry, I suspect that it either has a DEXT involved or some other disruption to the nub/driver stack above.
That leads to here:
Any way to retrieve Wi-Fi controller info in daemon code?
Yes. Here's the rest of what IOServiceGetMatchingServices class reference says:
"To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up."
For the iteration side, that generally means either finding a service "close" to your final target and using IORegistryEntryGetChildIterator() to iterate it's child, or simply using IORegistryCreateIterator() to iterate through the entire registry.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware