📄 network device drivers.htm
字号:
vast amounts of data being queued to a socket. After a limit is
hit, data is discarded. It is up to the application to read
fast enough, or as in TCP, for the protocol to do flow control
over the network. TCP actually tells the sending machine to
shut up when it can no longer queue data.
<p>On the sending side, <tt>sock_alloc_send_skb()</tt> handles
signal handling, the non blocking flag, and all the semantics
of blocking until there is space in the send queue so you
cannot tie up all of memory with data queued for a slow
interface. Many protocol send routines have this function doing
almost all the work:
</p><pre> skb=sock_alloc_send_skb(sk,....)
if(skb==NULL)
return -err;
skb->sk=sk;
skb_reserve(skb, headroom);
skb_put(skb,len);
memcpy(skb->data, data, len);
protocol_do_something(skb);
</pre>
<p>Most of this we have met before. The very important line is
<tt>skb->sk=sk</tt>. The <tt>sock_alloc_send_skb()</tt> has
charged the memory for the buffer to the socket. By setting
<tt>skb->sk</tt> we tell the kernel that whoever does a
<tt>kfree_skb()</tt> on the buffer should cause the socket to
be credited the memory for the buffer. Thus when a device has
sent a buffer and frees it the user will be able to send more.
</p><h3>Network Devices</h3>
<p>All Linux network devices follow the same interface although
many functions available in that interface will not be needed
for all devices. An object oriented mentality is used and each
device is an object with a series of methods that are filled
into a structure. Each method is called with the device itself
as the first argument. This is done to get around the lack of
the C++ concept of <tt>this</tt> within the C language.
</p><p>The file drivers/net/skeleton.c contains the skeleton of a
network device driver. View or print a copy from a recent
kernel and follow along throughout the rest of the article.
</p><h3>Basic Structure</h3>
<center><img src="network%20device%20drivers_files/fig7.gif"></center>
<p>Each network device deals entirely in the transmission of
network buffers from the protocols to the physical media, and
in receiving and decoding the responses the hardware generates.
Incoming frames are turned into network buffers, identified by
protocol and delivered to <tt>netif_rx()</tt>. This function
then passes the frames off to the protocol layer for further
processing.
</p><p>Each device provides a set of additional methods for the
handling of stopping, starting, control and physical
encapsulation of packets. These and all the other control
information are collected together in the device structures
that are used to manage each device.
</p><h3>Naming</h3>
<p>All Linux network devices have a unique name. This is not in
any way related to the file system names devices may have, and
indeed network devices do not normally have a filesystem
representation, although you may create a device which is tied
to device drivers. Traditionally the name indicates only the
type of a device rather than its maker. Multiple devices of the
same type are numbered upwards from 0. Thus ethernet devices
are known as ``eth0'', ``eth1'', ``eth2'' etc. The naming
scheme is important as it allows users to write programs or
system configuration in terms of ``an ethernet card'' rather
than worrying about the manufacturer of the board and forcing
reconfiguration if a board is changed.
</p><p>The following names are currently used for generic devices:
</p><dl>
<dt>eth<i>n</i>
</dt><dd>Ethernet controllers, both 10 and 100Mb/second
</dd><dt>tr<i>n</i>
</dt><dd>Token ring devices.
</dd><dt>sl<i>n</i>
</dt><dd>SLIP devices. Also used in AX.25 KISS mode.
</dd><dt>ppp<i>n</i>
</dt><dd>PPP devices both asynchronous and synchronous.
</dd><dt>plip<i>n</i>
</dt><dd>PLIP units. The number matches the printer port.
</dd><dt>tunl<i>n</i>
</dt><dd>IPIP encapsulated tunnels
</dd><dt>nr<i>n</i>
</dt><dd>NetROM virtual devices
</dd><dt>isdn<i>n</i>
</dt><dd>ISDN interfaces handled by isdn4linux. <a href="#isdn">(*)</a>
</dd><dt>dummy<i>n</i>
</dt><dd>Null devices
</dd><dt>lo
</dt><dd>The loopback device
</dd></dl>
<a name="isdn">(*)</a> At least one ISDN interface is an
ethernet impersonator, that is the Sonix PC/Volante driver.
Therefore, it uses an ``eth'' device name as it behaves in all
aspects as if it was ethernet rather than ISDN.
<p>If possible, a new device should pick a name that reflects
existing practice. When you are adding a whole new physical
layer type you should look for other people working on such a
project and use a common naming scheme.
</p><p>Certain physical layers present multiple logical interfaces
over one media. Both ATM and Frame Relay have this property, as
does multi-drop KISS in the amateur radio environment. Under
such circumstances a driver needs to exist for each active
channel. The Linux networking code is structured in such a way
as to make this managable without excessive additional code,
and the name registration scheme allows you to create and
remove interfaces almost at will as channels come into and out
of existance. The proposed convention for such names is still
under some discussion, as the simple scheme of ``sl0a'',
``sl0b'', "sl0c" works for basic devices like multidrop KISS,
but does not cope with multiple frame relay connections where a
virtual channel may be moved across physical boards.
</p><h3>Registering A Device</h3>
<p>Each device is created by filling in a <tt>struct
device</tt> object and passing it to the
<tt>register_netdev(struct device *)</tt> call. This links your
device structure into the kernel network device tables. As the
structure you pass in is used by the kernel, you must not free
this until you have unloaded the device with <tt>void
unregister_netdev(struct device *)</tt> calls. These calls are
normally done at boot time, or module load and unload.
</p><p>The kernel will not object if you create multiple devices with
the same name, it will break. Therefore, if your driver is a
loadable module you should use the <tt>struct device
*dev_get(const char *name)</tt> call to ensure the name is not
already in use. If it is in use, you should fail or pick
another name. You may not use <tt>unregister_netdev()</tt> to
unregister the other device with the name if you discover a
clash!
</p><p>A typical code sequence for registration is:
</p><pre>int register_my_device(void)
{
int i=0;
for(i=0;i<100;i++)
{
sprintf(mydevice.name,"mydev%d",i);
if(dev_get(mydevice.name)==NULL)
{
if(register_netdev(&mydevice)!=0)
return -EIO;
return 0;
}
}
printk("100 mydevs loaded. Unable to load more.\n");
return -ENFILE;
}
</pre>
<h3>The Device Structure</h3>
<p>All the generic information and methods for each network
device are kept in the device structure. To create a device you
need to fill most of these in. This section covers how they
should be set up.
</p><h3>Naming</h3>
First, the name field holds the device name. This is a string
pointer to a name in the formats discussed previously. It may
also be <tt>" "</tt> (four spaces), in which case the kernel
will automatically assign an eth<i>n</i> name to it. This is a
special feature that is best not used. After Linux 2.0, we
intend to change to a simple support function of the form
<tt>dev_make_name("eth")</tt>.
<h3>Bus Interface Parameters</h3>
<p>The next block of parameters are used to maintain the
location of a device within the device address spaces of the
architecture. The <tt>irq</tt> field holds the interrupt (IRQ)
the device is using. This is normally set at boot, or by the
initialization function. If an interrupt is not used, not
currently known, or not assigned, the value zero should be
used. The interrupt can be set in a variety of fashions. The
auto-irq facilities of the kernel may be used to probe for the
device interrupt, or the interrupt may be set when loading the
network module. Network drivers normally use a global int
called <tt>irq</tt> for this so that users can load the module
with <tt>insmod mydevice irq=5</tt> style commands. Finally,
the IRQ may be set dynamically from the ifconfig command. This
causes a call to your device that will be discussed later on.
</p><p>The <tt>base_addr</tt> field is the base I/O space address the
device resides at. If the device uses no I/O locations or is
running on a system with no I/O space concept this field should
be zero. When this is user settable, it is normally set by a
global variable called <tt>io</tt>. The interface I/O address
may also be set with ifconfig.
</p><p>Two hardware shared memory ranges are defined for things like
ISA bus shared memory ethernet cards. For current purposes, the
<tt>rmem_start</tt> and <tt>rmem_end</tt> fields are obsolete
and should be loaded with 0. The <tt>mem_start</tt> and
<tt>mem_end</tt> addresses should be loaded with the start and
end of the shared memory block used by this device. If no
shared memory block is used, then the value 0 should be stored.
Those devices that allow the user to specify this parameter use
a global variable called <tt>mem</tt> to set the memory base,
and set the <tt>mem_end</tt> appropriately themselves.
</p><p>The <tt>dma</tt> variable holds the DMA channel in use by the
device. Linux allows DMA (like interrupts) to be automatically
probed. If no DMA channel is used, or the DMA channel is not
yet set, the value 0 is used. This may have to change, since
the latest PC boards allow ISA bus DMA channel 0 to be used by
hardware boards and do not just tie it to memory refresh. If
the user can set the DMA channel the global variable
<tt>dma</tt> is used.
</p><p>It is important to realise that the physical information is
provided for control and user viewing (as well as the driver's
internal functions), and does not register these areas to
prevent them being reused. Thus the device driver must also
allocate and register the I/O, DMA and interrupt lines it
wishes to use, using the same kernel functions as any other
device driver. [See the recent Kernel Korner articles on
writing a character device driver in issues 23, 24, 25, 26, and
28 of <a href="http://www.ssc.com/lj">Linux Journal</a>.]
</p><p>The <tt>if_port</tt> field holds the physical media type for
multi-media devices such as combo ethernet boards.
</p><h3>Protocol Layer Variables</h3>
<p>In order for the network protocol layers to perform in a
sensible manner, the device has to provide a set of capability
flags and variables. These are also maintained in the device
structure.
</p><p>The <tt>mtu</tt> is the largest payload that can be sent over
this interface (that is, the largest packet size not including
any bottom layer headers that the device itself will provide).
This is used by the protocol layers such as IP to select
suitable packet sizes to send. There are minimums imposed by
each protocol. A device is not usable for IPX without a 576
byte frame size or higher. IP needs at least 72 bytes, and does
not perform sensibly below about 200 bytes. It is up to the
protocol layers to decide whether to co-operate with your
device.
</p><p>The <tt>family</tt> is always set to <tt>AF_INET</tt> and
indicates the protocol family the device is using. Linux allows
a device to be using multiple protocol families at once, and
maintains this information solely to look more like the
standard BSD networking API.
</p><p>The interface hardware type (type) field is taken from a table
of physical media types. The values used by the ARP protocol
(see RFC1700) are used for those media supporting ARP and
additional values are assigned for other physical layers. New
values are added when neccessary both to the kernel and to
<b>net-tools</b> which is the package containing programs like
<b>ifconfig</b> that need to be able to decode this field. The
fields defined as of Linux pre2.0.5 are:<br>
<b>From RFC1700:</b>
</p><dl>
<dt><tt>ARPHRD_NETROM</tt></dt><dd>NET/ROM(tm) devices.
</dd><dt><tt>ARPHRD_ETHER</tt></dt><dd>10 and 100Mbit/second ethernet.
</dd><dt><tt>ARPHRD_EETHER</tt></dt><dd>Experimental Ethernet (not used).
</dd><dt><tt>ARPHRD_AX25</tt></dt><dd>AX.25 level 2 interfaces.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -