I have tried extending IOUserNetworkEthernet
and calling RegisterEthernetInterface()
. This works perfectly for one ethernet interface, though the driver crashes when RegisterEthernetInterface
is called a second time (doesn't return an error code). I have tried registering with separate queues.
Another approach was extending IOUserClient
instead, and calling IOService::Create
to create child IOUserNetworkEthernet instances. Everything about this approach works (the children appear within ioreg). However, once I call RegisterEthernetInterface
on just one of the children, macOS crashes.
How would I go about creating a dext with multiple ethernet interfaces? Have I been approaching it the right way?
Appreciate any help.
I haven't yet implemented an ethernet dext myself, but based on my experience with using DriverKit for other types of drivers and knowing its design goals, I have an idea what the solution might be.
First off, let's clarify: you're implementing either a virtual ethernet device, or you're building a driver for hardware that unites multiple independent ports in one physical device. In the former case (I'm guessing this is what you're doing based on your IOUserClient
comment), your driver will be matching IOUserResources
and you create the ethernet driver instance when you receive the corresponding message from your user space component.
Now, DriverKit design: DriverKit is built around a goal of keeping the driver instance for each device in its own separate process. Sort of circling back to the microkernel idea. Specifically, this means that multiple devices that use the same driver will each create an independent instance of that driver in its own process. This very likely means that NetworkingDriverKit was never designed to support more than one instance of IOUserNetworkEthernet
, because they are seen as separate devices. Hence the crashes.
OK, what do we do about it? Use DriverKit the way it was intended. Put each virtual ethernet adapter in its own driver instance. This gets a bit tricky. I think this should work:
IOUserResources
. It's a simple IOService
class which listens for the signal (presumably IOUserClient
) to create or destroy a virtual ethernet device. When creating a virtual ethernet device, you need that to run in its own driver instance though. (For an actual device with multiple ports, this would match the USB/PCI device nub, manage bus communication with the device, and enumerate the ports.)IOUserNetworkEthernet
subclass, create an instance of a "nub" class and attach it to your central control class instance. Call RegisterService()
in its startup code, so it's considered for IOKit matching.IOUserNetworkEthernet
-derived class to "drive" the nub. Once the virtual ethernet device is ready to use, call RegisterEthernetInterface()
.2 extra things to note:
I'm not sure how you'd go about shutting down an individual virtual ethernet device, you could try calling Terminate()
on either it or the nub it's matched on and see what happens.