Packet Reception

Receiving data from the network is trickier than transmitting it because an sk_buff must be allocated and handed off to the upper layers from within an interrupt handler--the best way to receive a packet is through an interrupt, unless the interface is a purely software one like snull or the loopback interface. While it is possible to write polling drivers, and a few exist in the official kernel as well, interrupt-driven operation is much better, both in data throughput and in computational demands. Since the vast majority of network interfaces is interrupt-driven, I won’t talk about the polling implementation, which just exploits kernel timers.

The implementation of snull separates the hardware details from the device-independent housekeeping. The function snull_rx is thus called after the hardware has received the packet and it is already in the computer’s memory. snull_rx therefore receives a pointer to the data and the length of the packet. The function’s sole responsiblity is to send the packet and some additional information to the upper layers of networking code. This code is independent of the way the data pointer and length are obtained.

void snull_rx(struct device *dev, int len, unsigned char *buf)
{
    struct sk_buff *skb;
    struct snull_priv *privp = (struct snull_priv *)dev->priv;
    /*
     * The packet has been retrieved from the transmission
     * medium. Build an skb around it, so upper layers can handle it
     */

    skb = dev_alloc_skb(len+2);
    if (!skb) {
        printk("snull rx: low on mem
");
        return;
    }
    memcpy(skb_put(skb, len), buf, len);

    /* Write metadata, and then pass to the receive level */
    skb->dev = dev;
    skb->protocol = eth_type_trans(skb, dev);
    skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
    privp->stats.rx_packets++;
    netif_rx(skb);
    return;
}

The function is sufficiently general to act as a template for any network driver, but some explanation is necessary before you can reuse this code fragment with confidence.

Note that the buffer allocation function wants to know the data length. This avoids wasting memory when calling kmalloc. The allocation function is called with atomic priority by dev_alloc_skb, which can therefore be used safely at interrupt time. The kernel offers other interfaces to socket-buffer allocation, but they are not worth introducing here; socket buffers are explained in detail in Section 14.8, later in this chapter.

Once there is a valid skb pointer, the packet data is copied into the buffer by calling memcpy; the skb_put function updates the end-of-data pointer in the buffer and returns a pointer to the newly created space.

Unfortunately, there isn’t enough information in the packet’s headers to correctly handle the network layer--the dev and protocol fields must be assigned before the buffer is passed upstairs. Then we need to specify how checksumming is to be performed on the packet (snull does not perform any checksums). The possible policies for skb->ip_summed are:

CHECKSUM_HW

The board performs checksums in hardware. An example of a hardware checksum is the Sparc HME interface.

CHECKSUM_NONE

Checksums are done completely in software. This is the default in newly allocated buffers.

CHECKSUM_UNNECESSARY

Don’t do any checksums. This is the policy in snull and in the loopback interface.

The checksumming options and ip_summed are missing from the 1.2 kernel versions.

Finally, the driver updates its statistics counter to record that a packet has been received. The statistics structure is made up of several fields; the most important are rx_packets and tx_packets, which contain the number of packets received and transmitted. All the fields are thoroughly described later in Section 14.13.

The last step in packet reception is performed by netif_rx, which hands off the socket buffer to the upper layers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.202.45