嵌入式linux中文站在线图书

Previous Page
Next Page

13.2. Executing the Right Protocol Handler

For each network protocol, regardless of its layer, there is one initialization function. This includes L3 protocols such as IPv4 and IPv6, link layer protocols like ARP, and so on. For a protocol included statically in the kernel, the initialization function executes at boot time; for a protocol compiled as a module, the initialization function executes when the module is loaded. The function allocates internal data structures, notifies other subsystems about the protocol's existence, registers files in /proc, and so on. A key task is to register a handler in the kernel that handles the traffic for a protocol.

In this section, for the sake of simplicity, I'll show how a device driver (which operates on L2) invokes an L3 protocol, but the same principle applies to any protocol on any layer.

When the device driver receives a frame, it stores it into an sk_buff buffer data structure and it initializes the protocol field shown here:

struct sk_buff
{
        ... ... ...
        unsigned short  protocol;
        ... ... ...
};

The value in this field can be an arbitrary value used by the kernel to identify a given protocol, or a field of a MAC header in the incoming frame. The field is consulted by

Figure 13-5. Frame decapsulation, layer by layer, at Server Y


the kernel function netif_receive_skb (described in Chapter 10) to determine which function handler to execute to process the packet at L3. See Figure 13-6.

Figure 13-6. netif_receive_skb processes according to the protocol field of the sk_buff buffer


Most of the values used by the kernel to refer to the protocols in the protocol field are listed in include/linux/if_ether.h with the name ETH_P_XXX. Despite the ETH prefix, not all names refer to Ethernet hardware. As Table 13-1 shows, they can cover a wide range of activities. Table 13-1 lists the values used internally by the kernel, which are assigned directly to skb->protocol by device drivers instead of being extracted from a frame header. (The ones omitted from the table are not assigned a function handler.) The first row of the table, for instance, indicates that the kernel handler ipx_rcv is used to process an incoming packet whose skb->protocol field is ETH_P_802_3.

Table 13-1. Internal protocols

Symbol

Value

Function handler

ETH_P_802_3

0x0001

ipx_rcv

ETH_P_AX25

0x0002

ax25_kiss_rcv

ETH_P_ALL

0x0003

This is not a real protocol. It is used as a wildcard for a handler such as a packet sniffer that listens to all the protocols.

ETH_P_802_2

ETH_P_TR_802_2

0x0004

0x0011

llc_rcv

ETH_P_WAN_PPP

0x0007

sppp_rcv

ETH_P_LOCALTALK

0x0009

ltalk_rcv

ETH_P_PPPTALK

0x0010

atalk_rcv

ETH_P_IRDA

0x0017

irlap_driver_rcv

ETH_P_ECONET

0x0018

econet_rcv

ETH_P_HDLC

0x0019

hdlc_rcv


Not all the ETH_P_XXX values are assigned a handler. They can be left unassigned in two circumstances:

Unfortunately, it is not always sufficient to extract a field from the L2 header to figure out which handler to invoke; the association between skb->protocol and the protocol handler that will process the frame is not always one-to-one. There are cases where the protocol handler for a given ETH_P_XXX will actually just read other parameters from the frame header (without processing the frame) and hand the frame to another protocol handler that will process it. An example is the ETH_P_802_2 handler.

As described in Chapter 10, netif_receive_skb is the function that dispatches ingress frames to the right protocol handlers. When there is no handler for a specific protocol, the frame is dropped.

In special cases, a single packet can be delivered to multiple handlers. This is the case, for instance, when packet sniffers are running. This mode of operation, sometimes referred to as promiscuous mode , is listed as ETH_P_ALL in Table 13-1. This type of handler is generally not used to process packets for recipients, but just to snoop on a given device or set of devices for the purposes of debugging or collecting statistics.

13.2.1. Special Media Encapsulation

Ethernet is by far the most common mechanism used for implementing both shared and point-to-point network connections. In this book, we always refer to Ethernet device drivers when talking about L2. However, Linux allows you to use any of the most common media available on modern PCs to carry IP traffic (and sometimes any network protocol traffic). Examples of media that can be used to transport IP include the serial and parallel ports (SLIP/PLIP/PPP), FireWire (eth1394), USB, Bluetooth, Infrared Data Association (IrDA), etc.

Such media define network devices as abstractions on top of the generic ports, usually by means of extensions to the generic media device driver. Such virtual devices look like real NICs to the upper layers.

Here is how reception and transmission are implemented on these virtual network devices:


Transmission

The net_device's hard_start_xmit function pointer of the virtual device is initialized by the device driver to a routine that will encapsulate the IP packet (let's assume it was an IP packet) according to the protocol used by the media.


Reception

When the generic driver receives data from one of its ports, it strips the media headers (as an Ethernet device driver would strip the Ethernet header), initializes skb->protocol, and notifies the upper layer with a call to netif_rx. When these media are used for point-to-point connections only, there is no need for a link layer header, so skb->protocol is statically initialized to ETH_P_IP; in the other cases, the media encapsulation may include a fake Ethernet header too, so skb->protocol is initialized with eth_type_trans routines (as real Ethernet drivers are).

How exactly the generic device driver of a given media type interfaces to the virtual network device is an implementation detail. Depending on the medium, it may offer a synchronous or asynchronous interface, use of buffering both on receive and transmit paths, etc.


Previous Page
Next Page