The most important tasks performed by network interfaces are data transmission and reception. I’ll start with transmission because it is slightly easier to understand.
Whenever the kernel needs to transmit a data packet, it calls the
hard_start_transmit method to put the data on an outgoing queue.
Each packet handled by the kernel is contained in a socket buffer
structure (struct sk_buff
), whose definition is found in
<linux/skbuff.h>
. The structure gets its name from the Unix
abstraction used to represent a network connection, the socket.
Even if the
interface has nothing to do with sockets, each network packet belongs
to a socket in the higher network layers, and the input/output buffers
of any socket are lists of struct sk_buff
structures. The same
sk_buff
structure is used to host network data throughout all the Linux network
subsystems, but a socket buffer is just a packet as far as the interface
is concerned.
A pointer to sk_buff
is usually called skb
, and I’m
going to follow this practice both in the sample code and in the text.
The socket buffer is a complex structure, and the kernel
offers a number of functions to act on it. The functions are described
later in Section 14.8--for now a few basic facts about
sk_buff
are enough for us to write a working driver. Also,
I prefer to show how things work before delving into boring details.
The socket buffer passed to hard_start_xmit contains the
physical packet, complete with the transmission-level headers. The
interface doesn’t need
to modify the data being transmitted. skb->data
points to the
packet being transmitted, and skb->len
is its length, in
octets.
The snull packet transmission code is listed below; the physical transmission machinery has been isolated in another function because every interface driver must implement it according to the specific hardware being driven.
int snull_tx(struct sk_buff *skb, struct device *dev) { int len, retval=0; char *data; if (dev->tbusy) { /* shouldn't happen */ return -EBUSY; } if (skb == NULL) { PDEBUG("tint for %p ",dev); dev_tint(dev); /* we are ready to transmit */ return 0; } dev->tbusy = 1; /* transmission is busy */ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* minimum len */ data = skb->data; dev->trans_start = jiffies; /* save the timestamp */ /* actual deliver of data is device-specific, and not shown here */ snull_hw_tx(data, len, dev); tx_done: skb->free=1; dev_kfree_skb(skb, FREE_WRITE); /* release it */ return retval; /* zero == done; nonzero == fail */ }
The transmission function thus performs only some sanity checks
on the packet and transmits the data through the hardware-related
function. dev->tbusy
is cleared when an interrupt
signals a ``transmission done'' condition.
3.136.154.103