Linux驱动之网络驱动应用

网络驱动应用

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/interrupt.h> /* mark_bh */
#include <linux/in.h>
#include <linux/netdevice.h>   /* struct device, and other headers */
#include <linux/etherdevice.h> /* eth_type_trans */
#include <linux/ip.h>          /* struct iphdr */
#include <linux/tcp.h>         /* struct tcphdr */
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/in6.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <linux/platform_device.h>

//如果需要随机MAC地址则定义该宏
#define MAC_AUTO

static struct net_device *mynet_devs;

//网络设备结构体,作为net_device->priv
struct mynet_priv{
	struct net_device_stats stats;    //有用的统计信息
	int status;                       //网络设备的状态信息,是发完数据包还是接收到网络数据包
	int rx_packetlen;                 //接收到的数据包长度
	u8 *rx_packtdata;                 //接收到的数据
	struct sk_buff *skb;              //socket buffer结构体,网络各层之间传送数据都是通过该结构体实现
	spinlock_t lock;                  //自旋锁
};

//网络接口的打开函数
int mynet_open(struct net_device *dev)
{
	printk("mynet_open\n");

#ifndef MAC_AUTO
	int i;
	for(i=0; i<6; i++)
		dev->dev_addr[i]=0xaa;
#else
	random_ether_addr(dev->dev_addr);  //随机源地址
#endif
	netif_start_queue(dev);            //打开传输队列,这样才能进行数据传输

	return 0;
}

int mynet_release(struct net_device *dev)
{
	printk("mynet_release\n");
	//当网络接口关闭的时候,调用stop方法,这个函数表示不能再发送数据
	netif_stop_queue(dev);

	return 0;
}

//接包函数
void mynet_rx(struct net_device *dev,int len,unsigned char *buf)
{
	struct sk_buff *skb;
	struct mynet_priv *priv = (struct mynet_priv *)dev->ml_priv;
	//分配一个socket buffer,并且初始化skb->data,skb->tail和skb->head
	skb = dev_alloc_skb(len+2);
	if(!skb)
	{
		printk("gecnet rx: low on mem - packet dropped\n");
		priv->stats.rx_dropped++;
		return;
	}
	skb_reserve(skb,2);
	memcpy(skb_put(skb,len),buf,len);//skb_put是把数据写入到socket buffer

	skb->dev = dev;
	skb->protocol = eth_type_trans(skb,dev);//返回的是协议号
	skb->ip_summed = CHECKSUM_UNNECESSARY;//此处不校验
	priv->stats.rx_packets++;   //接收到包的个数加1

	priv->stats.rx_bytes += len;//接收到包的长度
	printk("mtnet rx \n");
	netif_rx(skb);//通知内核已经接收到包,并且封装成socket buffer传到上层
	return;	
}

//真正的处理的发送数据包
//模拟一个网络向另一个网络发送数据包
void mynet_hw_tx(char *buf,int len,struct net_device *dev)
{
	//目标设备结构体,net_device存储一个网络接口的重要信息,是网络驱动程序
	struct net_device *dest;
	struct mynet_priv *priv;

	if(len < sizeof(struct ethhdr) + sizeof(struct ipthr))
	{
		printk("mynet:Hmm... packet too shaort (%i octets)\n",len);
		return ;
	}

	dest = mynet_devs;
	priv = (struct mynet_priv *)dest->ml_priv;  //目标dest中的priv
	priv->rx_packetlen = len;
	priv->rx_packtdata = buf;

	printk("mynet tx \n");
	dev_kfree_skb(priv->skb);
}

//发包函数
void mynet_tx(struct sk_buff *skb,struct net_device *dev)
{
	int len;
	char *data;
	struct mynet_priv *priv = (struct mynet_priv *)dev->ml_priv;

	if(skb == NULL)
	{
		printk("net_device %p, skb %p\n",dev,skb);
		return 0;
	}

	len =skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;//ETH_ZLEN是所发的最小的数据包长度
	data = skb->data;//将要发送的数据包中的数据部分
	priv->skb = skb;
	mynet_hw_tx(data,len,dev);//真正的发送函数

	return 0;
}

//设备初始化函数
int mynet_init(struct net_device *dev)
{
	printk("astoncnet_init\n");

    ether_setup(dev);//填充一些以太网中的设备结构体的项
    
    /* keep the default flags, just add NOARP */
    dev->flags           |= IFF_NOARP;

//为priv分配内存
	dev->ml_priv = kmalloc(sizeof(struct mynet_priv), GFP_KERNEL);
	if (dev->ml_priv == NULL)
		return -ENOMEM;
    memset(dev->ml_priv, 0, sizeof(struct mynet_priv));
    spin_lock_init(&((struct mynet_priv *)dev->ml_priv)->lock);
	
    return 0;
}
static const struct net_device_ops mt_netdev_ops = {
		.ndo_open          = mynet_open,   //打开网卡      对应ifconfig xxx up
		.ndo_stop          = mynet_release, //关闭网卡      对应ifconfig xxx down
		.ndo_start_xmit    = mynet_tx,     //开启数据包传送
		.ndo_init          = mynet_init,   //初始化网卡硬件
};

static void my_plat_net_release(struct device * dev)
{
	printk("my_plat_net_release\n");
}

static int __devinit my_net_probe(struct platform_device * pdev)
{
	int result = 0;

	mynet_devs = alloc_etherdev(sizeof(struct net_device));
	mynet_devs->netdev_ops = &mtnet_netdev_ops;

	strcpy(mynet_devs->name,"mynet0");
	if((result = register_netdev(mynet_devs)))
		printk("my_net:error %i registering device \"%s\"\n",result,mynet_devs->name);
	return 0;
}

static int  __devexit  aston_net_remove(struct platform_device *pdev)   //设备移除接口
{
        kfree(mynet_devs->ml_priv);
        unregister_netdev(mynet_devs);
        return 0;
}

static struct platform_device my_net =
{
	.name     = "my_net",
	.id      = -1,
	.dev     = {
		.release   = my_plat_net_release,
	},	
};

static struct platform_driver my_net_driver =
{
	.probe     = my_net_probe,
	.remove      = __devexit_p(my_net_remove),
	
	.driver     = {
		.name     = "my_net",
		.owner = THIS_MODULE,
	},	
};

static int my_net_init(void)
{
	
	printk("my_net_init\n");

	platform_device_register(&my_net);
	return platform_driver_register(&my_net_driver);
}

static void my_net_exit(void)
{
	
	platform_driver_unregister(&my_net_driver);
	platform_device_unregister(&my_net);
}
module_init(my_net_init);
module_exit(my_net_exit);

MODULE_LICENSE("GPL");


编译成功并加载.ko文件后,使用ifconfig命令即可看见新的一个虚拟网卡出现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值