world leader in high performance signal processing
Trace: » netdev

Network Device Drivers

The main objective of a network device driver is to allow data to flow to and from the network hardware device. The Network stack handles the generation and reception of network packets. The network device driver, primarily, transfers these packets to and from the network hardware.

The Big Picture

A Network device driver will describe or define the network device to the network interface layer. This gives the system the ability to identify packets arriving from the hardware and route internal packets destined for the network attached to the hardware. In defining the hardware the device driver will also configure some functions to be used to set up the device and send / receive data to and from the hardware.

The Net Device structure

The network device structure is the master structure used to define the network device.

After detecting the network device the network device driver needs to set up this structure to allow the network interface code to define the device in the network system architecture.

A typical structure is established with a call to alloc_etherdev(sizeof(struct net_local)). This will set up the ethernet name of the device (eth%d).

The number (%d) will be assigned automatically by the kernel.

An ethernet name consists of a generic name followed by a number. Each time a new device of a given generic name is discovered the number is incremented. This allows devices such as eth0 eth1 and eth2 to be defined.

The following is a subset of the functions that need to be defined for a simple network device.

        dev->open               = net_open;
        dev->stop               = net_close;
        dev->hard_start_xmit    = net_send_packet;
        dev->get_stats          = net_get_stats;
        dev->set_multicast_list = &set_multicast_list;
 
        dev->tx_timeout         = &net_tx_timeout;
        dev->watchdog_timeo     = MY_TX_TIMEOUT;

Outline of a Simple Network Device Driver

A simple network device driver performs as follows

  • Detect the arrival of network packets from the hardware device
  • Detct the availabliity of a packet to send to the hardware from the

network stack.

  • Detect the requirement of the network interface to start (or open ) an

interface on a selected hardware device.

  • Set up a network device structure for use by the network interface layer.
  • Handle any modifications required to the packet header for data to be

sent on the hardware device

  • Manage traffic on the device, telling the Network interface to start and

stop sending packets, as hardware transmit buffers fill and empty.

  • Collect network statistics data from the device.

More sophisticated drivers ( for more sophisticated devices) also manage hardware buffers and DMA based data tranfers.

Incoming Network data

Network device drivers deal with a network data structure called a skbuf (see linux/include/linux/skbuff.h) .

These structures are used to contain network data and header information ( as well as lots of other details ).

A data packet arriving from a network device is placed into a skbuf and then passed into the system network interface.

The following code sequence shows this process in action it is taken from linux/drivers/net/isa-skeleton.c . This code is normally part of the interrupt service routine for an incoming network packet.

 struct sk_buff *skb;
   int status
   int pkt_len
 
   // ioaddr is the address of the network device
   status = inw(ioaddr);
   pkt_len = inw(ioaddr);
 
 
   // get a skb
   skb = dev_alloc_skb(pkt_len);
 
   // define the device that got the packet.
   skb->dev = dev;
 
   // copy data from the device to the skb->data segment
   memcpy(skb_put(skb,pkt_len),
                      (void*)dev->rmem_start,
 
   // give it to the network layer
   netif_rx(skb);
 
  // handle the accounts
  dev->last_rx = jiffies;
  lp->stats.rx_packets++;
  lp->stats.rx_bytes += pkt_len;

More sophisticated drivers will preallocate the skbuf structures as part of a DMA area for incoming data and will then pass these preallocated buffers into the system network stack.

Outgoing Network data

Once a network device has been opened it has been registered with the kernel as a possible destination for outbound network packets. This normally means that the device has been given a network address and that it can start sending data.

The system network stack will identify data destined to this particular device driver and then issue a call to the hard_start_xmit that was registered during the hardware device setup. This function has the responsibility of sending the data packet to the device.

The data is in the form of a skbuf structure and the hardware device is defined in terms of a net_device structure.

A code sample shows this in action

static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
        struct net_local *np = netdev_priv(dev);
        int ioaddr = dev->base_addr;
        short length = skb->len;
 
        hardware_send_packet(ioaddr, buf, length);
        np->stats.tx_bytes += skb->len;
 
        dev->trans_start = jiffies;
      /* You might need to clean up and record Tx statistics here. */
        if (inw(ioaddr) == /*RU*/81)
                np->stats.tx_aborted_errors++;
        dev_kfree_skb (skb);
 
        return 0;
}

Opening a Network Device

This function handles the process of setting up the hardware to send and receive network packets.

This function is normally invoked in response to the ifconfig eth0 up user function.

In its simplest form it will kick off the device interrupts and start the network transmit queue. After this function any network packets directed to the hardware will start to arrive. Any incoming packets will also be sent into the system network interface subsystem.

static int
net_open(struct net_device *dev)
{
        struct net_local *np = netdev_priv(dev);
        int ioaddr = dev->base_addr;
 
        // get the device interrupt service routine set up
        if (request_irq(dev->irq, &net_interrupt, 0, cardname, dev)) {
                return -EAGAIN;
        }
 
        /* Reset the hardware here. Don't forget to set the station address. */
        chipset_init(dev, 1);
        outb(0x00, ioaddr);
 
        //record the open time
        np->open_time = jiffies;
 
        /* We are now ready to accept transmit requeusts from
         * the queueing layer of the networking.
         */
        netif_start_queue(dev);
 
        return 0;
}

Closing a Network Device

This function handles the process of shutting down the hardware and turning off the system network packet queue to the device.

This function is normally invoked in response to the **ifconfig eth0 down* user function.

In its simplest form it will turn off the device interrupts and stop the network transmit queue.

A simple example shows this in action.

static int
net_close(struct net_device *dev)
{
        struct net_local *np = netdev_priv(dev);
        int ioaddr = dev->base_addr;
 
        netif_stop_queue(dev);
 
        outw(0x00, ioaddr+0);   /* Release the physical interrupt line. */
 
        free_irq(dev->irq, dev);
 
        return 0;
}

Media Interface

A hardware network driver also often has the repsonsibility of managing the media interface device. This will handle the rate and type of communications the network device can manage. Normally a separate interrupt structure is established for the media interface.