Linux 网络设备驱动

一.网络设备驱动框架 

接收

将报文从设备驱动接受并送入协议栈

老API netif_if

编写网络设备驱动

步骤

1.注册一个网络设备

2.填充net_device_ops结构体

3.编写接收发送函数

// SPDX-License-Identifier: GPL-2.0-only
/*
 * This module emits "Hello, world" on printk when loaded.
 *
 * It is designed to be used for basic evaluation of the module loading
 * subsystem (for example when validating module signing/verification). It
 * lacks any extra dependencies, and will not normally be loaded by the
 * system unless explicitly requested by name.
 */


#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>

#include <linux/uaccess.h>
#include <linux/io.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>	/* For the statistics structure. */
#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <linux/net_tstamp.h>
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>
#include <linux/printk.h>
#include <linux/icmp.h>

#define DEBUG_TEST_NETDEV

#define TEST_NETDEV_NAME "test%d"
#define MAX_JUMBO_FRAME_SIZE         0x3F00

static struct net_device *test_netdev;
#ifdef DEBUG_TEST_NETDEV
static void dump_skb (struct sk_buff * skb) 
{
  print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET,
			 16, 1, skb->data, skb->len, true);
  return;
}
#endif
static int test_open(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return 0;
}
static int test_close(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return 0;
}
netdev_tx_t	test_xmit_frame(struct sk_buff *skb, struct net_device *dev)
{
	int len;
	struct ethhdr *ethh = eth_hdr(skb);
	struct iphdr *iph = ip_hdr(skb);
	struct icmphdr *icmph = icmp_hdr(skb);
	char mac_tmp[6];
	__be32 addr_tmp;
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	
#ifdef DEBUG_TEST_NETDEV
	dump_skb(skb);
#endif
	memcpy(mac_tmp, ethh->h_source, 6);
	memcpy(ethh->h_source, ethh->h_dest, 6);
	memcpy(ethh->h_dest, mac_tmp, 6);
	addr_tmp = iph->saddr;
	iph->saddr = iph->daddr;
	iph->daddr = addr_tmp;
	icmph->type = 0;
	icmph->checksum = 0;
	icmph->checksum = ip_compute_csum(icmph, iph->tot_len - iph->ihl);
	iph->check = 0;
	iph->check = ip_compute_csum(iph, iph->tot_len);
	
#ifdef DEBUG_TEST_NETDEV
	dump_skb(skb);
#endif
	skb_tx_timestamp(skb);

	/* do not fool net_timestamp_check() with various clock bases */
	skb->tstamp = 0;

	skb_orphan(skb);

	/* Before queueing this packet to netif_rx(),
	 * make sure dst is refcounted.
	 */
	skb_dst_force(skb);
	
	skb->protocol = eth_type_trans(skb, dev);



	len = skb->len;
	
	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
		test_netdev->stats.rx_bytes += len;
		test_netdev->stats.tx_bytes += len;
		test_netdev->stats.rx_packets++;
		test_netdev->stats.tx_packets++;
	}
	
	return NETDEV_TX_OK;
}

static void	test_set_rx_mode(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return;
}

static int test_set_mac(struct net_device *dev, void *addr)
{
	struct sockaddr *saddr = addr;
	printk("<%s:%d> mac: %02x:%02x:%02x:%02x:%02x:%02x\n",__FUNCTION__,__LINE__, 
		saddr->sa_data[0],saddr->sa_data[1],saddr->sa_data[2],saddr->sa_data[3],saddr->sa_data[4],saddr->sa_data[5]);
	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
	return 0;
}

static void test_tx_timeout (struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return;
}
static int test_change_mtu(struct net_device *dev, int new_mtu)
{
	printk("<%s:%d>: mtu: %d\n", __FUNCTION__,__LINE__, new_mtu);
	return 0;
}
static int test_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{

	printk("<%s:%d> cmd %d\n", __FUNCTION__,__LINE__, cmd);
	return 0;

}
static void test_netpoll(struct net_device *dev)
{
	printk("<%s:%d>\n", __FUNCTION__,__LINE__);
	return;
}
static netdev_features_t test_fix_features(struct net_device *dev, netdev_features_t features)
{
	
	printk("<%s:%d> features %llx\n", __FUNCTION__,__LINE__, dev->features);
	return features;
}
static int test_set_features(struct net_device *dev, netdev_features_t features)
{
	printk("<%s:%d> features %llx\n", __FUNCTION__,__LINE__, features);
	dev->features = features;
	return 1;
}
static void test_change_rx_flags(struct net_device *dev, int flags)
{
	printk("<%s:%d> flags %d\n", __FUNCTION__,__LINE__, flags);
}

static const struct net_device_ops test_netdev_ops = {
	.ndo_open			= test_open,
	.ndo_stop			= test_close,
	.ndo_start_xmit		= test_xmit_frame,
	.ndo_set_rx_mode	= test_set_rx_mode,
	.ndo_set_mac_address	= test_set_mac,
	.ndo_tx_timeout		= test_tx_timeout,
	.ndo_change_mtu		= test_change_mtu,
	.ndo_do_ioctl		= test_ioctl,
	.ndo_validate_addr	= eth_validate_addr,

#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= test_netpoll,
#endif
	.ndo_fix_features		= test_fix_features,
	.ndo_set_features		= test_set_features,
   	.ndo_change_rx_flags 	= test_change_rx_flags,


};


static int __init test_netdev_init(void)
{

	
	int ret = 0;
	pr_warn("init test netdev\n");
	test_netdev = alloc_etherdev(sizeof(struct net_device));
	if (!test_netdev)
		goto out;
	test_netdev->netdev_ops = &test_netdev_ops;
	strcpy(test_netdev->name, TEST_NETDEV_NAME);
	ret = register_netdev(test_netdev);
	if(ret)
		goto failed;
	test_netdev->min_mtu = ETH_ZLEN - ETH_HLEN;
	test_netdev->max_mtu = MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN);
	memset(test_netdev->dev_addr, 0x60, test_netdev->addr_len);
	return 0;
failed:
	free_netdev(test_netdev);
out:
	return 0;
}

module_init(test_netdev_init);

static void __exit test_netdev_exit(void)
{
	pr_warn("exit test netdev\n");
	unregister_netdev(test_netdev);
	free_netdev(test_netdev);

}

module_exit(test_netdev_exit);

MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
MODULE_LICENSE("GPL");

 test0就是我们的驱动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值