"Linux Driver: Network Device Driver"

I. Introduction

I have studied and analyzed the basic framework and construction process of character device drivers and block device drivers. This article goes on to learn about network device drivers. Network devices are designed for receiving and sending data, which does not correspond to device nodes of the file system. The communication between the kernel and network devices is completely different from the communication between the kernel and character devices and block devices. Network devices mainly use socket interfaces. The basic structure of the network device driver and the basic process of building a network device driver are introduced here.

Second, the structure of the network device driver

When building a specific network device driver, the main work we need to do is to write related functions in the device driver function layer to fill in the net_device data structure and register it with the kernel.
insert image description here

2.1 Network protocol interface layer

Provide a unified data packet sending and receiving interface for the network layer protocol. No matter whether the upper layer protocol is ARP or IP, the data is sent through the dev_queue_xmit() function, and the data is received through the netif_rx() function. The existence of this layer makes the upper layer protocol independent of specific devices.

2.2 Network device interface layer

Provide the protocol interface layer with a unified structure net_device used to describe the attributes and operations of specific network devices, which is the container for each function in the device driver function layer.

2.3 Device driver function layer

Each function interface designed by this layer is a specific member of the net_device data structure of the network device interface layer. It is a program that drives the network device hardware to complete the corresponding action. It starts the sending operation through the hard_start_xmit() function, and triggers the receiving operation through the interrupt on the network device .

2.4 Network equipment and media layer

The physical entity that completes the sending and receiving of data packets includes a network adapter and a specific transmission medium. The network adapter is physically driven by various functions in the device driver function layer.

Third, build a virtual network card driver

Register a virtual network card device with the kernel, and after manually setting the IP for the virtual device, you can ping through an ip on the same network segment at will.


/*
 * 参考 drivers\net\cs89x0.c
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/ip.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>

static struct net_device *vnet_dev;

static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)
{
    
    
	/* 参考LDD3 */
	unsigned char *type;
	struct iphdr *ih;
	__be32 *saddr, *daddr, tmp;
	unsigned char	tmp_dev_addr[ETH_ALEN];
	struct ethhdr *ethhdr;
	
	struct sk_buff *rx_skb;
		
	/*
	这里是使用了发送出去的sk_buff构建假的接收到的数据,即原来的是源mac发送给目的mac,现在调换一下
	就是原先的源mac变成目的mac,目的mac变成源mac,下面的IP也要调换
	*/
	// 从硬件读出/保存数据
	/* 
	对调"源/目的"的mac地址 
	*/
	ethhdr = (struct ethhdr *)skb->data;
	memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
	memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
	memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

	/* 对调"源/目的"的ip地址 */    
	ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
	saddr = &ih->saddr;
	daddr = &ih->daddr;

	tmp = *saddr;
	*saddr = *daddr;
	*daddr = tmp;
	
	//((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
	//((u8 *)daddr)[2] ^= 1;
	type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
	//printk("tx package type = %02x\n", *type);
	// 修改类型, 原来0x8表示ping
	*type = 0; /* 0表示reply */
	
	ih->check = 0;		   /* and rebuild the checksum (ip needs it) */
	ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
	
	// 构造一个sk_buff
	rx_skb = dev_alloc_skb(skb->len + 2);
	skb_reserve(rx_skb, 2); /* align IP on 16B boundary */	
	memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);

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

	// 提交sk_buff
	netif_rx(rx_skb);
}

static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
    
    
	static int cnt = 0;
	printk("virt_net_send_packet cnt = %d\n", ++cnt);

	/* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */
	netif_stop_queue(dev); /* 停止该网卡的队列 */
    /* ...... */           /* 把skb的数据写入网卡 */

	/*  
	由于这里是一个假的网络设备,没有收包能力,直接在这里构造一个假的sk_buff,上报。
	真实的网络设备驱动应该在一个网卡中断中,接收并处理数据后,再发送给上层处理。
	*/
	emulator_rx_packet(skb, dev);

	dev_kfree_skb (skb);   /* 释放skb */
	netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */

	/* 更新统计信息 */
	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;
	
	return 0;
}


static int virt_net_init(void)
{
    
    
	/* 1. 分配一个net_device结构体 */
	vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);;  /* alloc_etherdev */

	/* 2. 设置 */
	vnet_dev->hard_start_xmit = virt_net_send_packet;

	/* 设置MAC地址 */
    vnet_dev->dev_addr[0] = 0x08;
    vnet_dev->dev_addr[1] = 0x89;
    vnet_dev->dev_addr[2] = 0x89;
    vnet_dev->dev_addr[3] = 0x89;
    vnet_dev->dev_addr[4] = 0x89;
    vnet_dev->dev_addr[5] = 0x11;

    /* 设置下面两项才能ping通 */
	// 因为在真实的环境中,ping通其他的网络设备前需要先通过arp协议获取其MAC地址。
	// 而现在ping的设备是不存在的,所以通过设置该参数,默认对方存在,直接发送出数据
	// 即直接调用hard_start_xmit接口。
	vnet_dev->flags           |= IFF_NOARP;  
	vnet_dev->features        |= NETIF_F_NO_CSUM;	

	/* 3. 注册 */
	//register_netdevice(vnet_dev);
	register_netdev(vnet_dev);
	
	return 0;
}

static void virt_net_exit(void)
{
    
    
	unregister_netdev(vnet_dev);
	free_netdev(vnet_dev);
}

module_init(virt_net_init);
module_exit(virt_net_exit);

MODULE_LICENSE("GPL");


Four, summary

4.1 Data transmission process

Packet sending: the network protocol layer calls the dev_queue_xmit( ) interface of the network protocol interface layer to send the contract; the device driver function layer assigns a value to the hard_start_xmit member of the net_device structure of the network device interface layer, that is, provides the packet sending function; the dev_queue_xmit( ) function calls the sending function to pass the data through The network card transmits to other network devices.
Packet receiving: Generally, an interrupt is created in the device driver function layer, and the data transmitted by the network card is received in the interrupt, and then sent to the network protocol layer through the network protocol interface layer interface netif_rx for processing -> transport layer processing -> application layer processing .

4.2 The general process of building a network device driver (device driver function layer)

  • Call the alloc_netdev interface to apply for allocation of a net_device structure.
  • Set the net_device structure and provide at least one sending function.
  • Apply for a network card related interrupt according to the hardware circuit, receive the data sent by other devices received by the network card during the interrupt, and send it to the upper layer for processing through the netif_rx function.
  • Call the register_netdev interface to register the driver.

Guess you like

Origin blog.csdn.net/qq_40709487/article/details/127141333