In Linux, network interfaces don't have a device node in
/dev at all.
If you need the list of usable network interfaces e.g. in a script, look into
/sys/class/net/ directory; you'll see one symbolic link per interface. Each network interface that has a driver loaded will be listed.
Programmatically, you can use the
if_nameindex() syscall: see this answer on Stack Overflow.
Also, note that
/dev is the device filesystem.
The device-tree has a specific different meaning: it is a machine-readable description of a system's hardware composition. It is used on systems that don't have Plug-and-Play capable hardware buses, or otherwise have hardware that cannot be automatically discovered. As an example, Linux on ARM SoCs like Raspberry Pi uses a device tree.
The boot sequence of a RasPi is quite interesting: see this question on RasPi.SE.
In short, at boot time, under control of the
/boot/start.elf file, the GPU loads the appropriate
/boot/*.dtb and /boot/overlay/*.dtbo files before the main ARM CPU is started. The
*.dtb file is the compiled device tree in binary format. It describes the hardware that can be found on each specific RasPi model, and is produced from a device tree source file (.dts`) which is just text, formatted in a specific way.
The kernel's live image of the device-tree can be seen in: /sys/firmware/devicetree/base Per Ciro Santilli, it can be displayed in .dts format by:
sudo apt-get install device-tree-compiler
dtc -I fs -O dts /sys/firmware/devicetree/base
You can find the specification of the device tree file format here. The specification is intended to be OS-independent. You may also need the Device Tree Reference as clarification to some details.
So, the answer to your original question is like this:
- the Berkeley Sockets API gets the network interface from the kernel
- the kernel gets the essential hardware information from the device tree file
- the device tree file is loaded by the GPU with
/boot/start.elf according to configuration in
- the device tree file was originally created according to the hardware specifications of each RasPi model and compiled to the appropriate binary format.
The device tree scanning code is mostly concerned about finding a valid driver for each piece of hardware. It won't much care about each device's purpose: that's the driver's job.
The driver uses the appropriate
*_register_driver() kernel function to document its own existence, takes the appropriate part of the device tree information to find the actual hardware, and then uses other functions to register that hardware as being under its control. Once the driver has initialized the hardware, it uses the kernel's
register_netdev() function to register itself as a new network interface, which, among other things, will make the Sockets API (which is just another interface of the kernel, not an independent entity as such) aware that the network interface exists.
The driver is likely to register itself for other things too: it will list a number of
ethtool operations it supports for link status monitoring, traffic statistics and other low-level functions, and a driver for a wireless NIC will also use
register_wiphy() to declare itself as a wireless network interface with specific Wi-Fi capabilities.
The Linux TCP/IP stack has many interfaces: the Berkeley Sockets API is the side of it that will be the most familiar to application programmers. The netdev API is essentially the other, driver-facing side of the same coin.