虚拟网卡驱动

来源:互联网 发布:淘宝royce 假货 编辑:程序博客网 时间:2024/05/01 10:28

学习了linux驱动程序,模仿tun写了一个虚拟网卡驱动,非常简陋

 

[虚拟网卡设备] <----> [字符设备] <----> [NIC] 

设备虚拟网络卡设备,和字符设备,通过socket向虚拟网卡发送和接受的数据,可以通过字符设备进行读写.

通过一个用户空间程序,可以将字符设备和真实的网卡连接起来,并实现虚拟网卡和真实网卡的桥接

 

 

  1. #include <linux/module.h>
  2. #include <linux/errno.h>
  3. #include <linux/kernel.h>
  4. #include <linux/miscdevice.h>
  5. #include <linux/init.h>
  6. #include <linux/major.h>
  7. #include <linux/slab.h>
  8. #include <linux/fcntl.h>
  9. #include <linux/skbuff.h>
  10. #include <linux/netdevice.h>
  11. #include <linux/etherdevice.h>
  12. #include <linux/if.h>
  13. #include <linux/if_arp.h>
  14. #include <linux/if_ether.h>
  15. #define DBG(x...) printk(x)
  16. //#define DBG(x...)
  17. #define VNIC_MINOR  200
  18. #define READQ_SIZE  500
  19. #define SETIFUP     0xff0001
  20. #define SETIFDN     0xff0002
  21. #define SETIFRUN    0xff0003
  22. static LIST_HEAD(vnic_net_list);
  23. struct vnic_struct{
  24.     struct list_head list;              //设备链表
  25.     wait_queue_head_t read_head;        //等待队列
  26.     spinlock_t lock;                    //琐
  27.     struct sk_buff_head readq;          //收包队列
  28.     struct net_device *dev;             //net_device
  29.     struct net_device_stats stats;      //设备状态
  30.     
  31.     
  32. };
  33. loff_t no_chr_llseek(struct file *file, loff_t offset, int origin){
  34.     return -ESPIPE;
  35. }
  36. static int vnic_chr_open(struct inode *inode, struct file *file){
  37.     file->private_data = NULL;
  38.     return 0;
  39. }
  40. static int vnic_chr_close(struct inode *inode, struct file *file){
  41.     return 0;
  42. }
  43. static ssize_t vnic_chr_read(struct file * file, char __user * buf, 
  44.                 size_t count, loff_t *pos){
  45.     struct sk_buff *skb;
  46.     struct vnic_struct *vnic = file->private_data;
  47.     int len;
  48.     DECLARE_WAITQUEUE(wait, current);               //声明并初始化等待队列
  49.     add_wait_queue(&vnic->read_head, &wait);        //加入等待队列
  50.     
  51.     wait_event_interruptible(vnic->read_head, skb_queue_len(&vnic->readq)>0);
  52.     if(vnic == NULL){
  53.         DBG(KERN_INFO"vnic data wrong/n");
  54.         return -1;
  55.     }
  56.     skb = skb_dequeue(&vnic->readq);        //从收包队列中解包
  57.     if(skb == NULL){
  58.         DBG(KERN_INFO"no packet/n");
  59.         return 0;
  60.     }
  61.     netif_wake_queue(vnic->dev);            //重新唤醒收包队列(当队列满时,将停止收包,这边来唤醒)       
  62.     len = skb->len;
  63.     if(copy_to_user(buf, skb->data, len)){      //提交给用户空间
  64.         DBG(KERN_ERR"copy to use failed/n");
  65.     }
  66.     /*
  67.         统计状态维护
  68.     */
  69.     vnic->stats.tx_packets++;
  70.     vnic->stats.tx_bytes += len;
  71.     
  72.     kfree_skb(skb);                         //释放skb
  73.     remove_wait_queue(&vnic->read_head, &wait);     //移出等待队列
  74.     schedule();                             //放弃cpu
  75.     return len;
  76. }
  77. static ssize_t vnic_chr_write(struct file * file, const char __user * buf, 
  78.                  size_t count, loff_t *pos){
  79.     struct vnic_struct *vnic;
  80.     struct sk_buff *skb;
  81.     struct net_device *dev;
  82.     int len;
  83.     int align = 2;
  84.     vnic = file->private_data;
  85.     if(vnic == NULL){
  86.         DBG(KERN_DEBUG"write data wrong/n");
  87.         return -1;
  88.     }
  89.     dev = vnic->dev;
  90.     len = count;
  91.     if(len > dev->mtu + ETH_HLEN){              //包过大
  92.         vnic->stats.rx_dropped++;
  93.         DBG(KERN_INFO"packet too long/n");
  94.         return -1;
  95.     }
  96.     
  97.     skb = alloc_skb(len + align, GFP_KERNEL);   //分配skb
  98.     if(skb == NULL){
  99.         vnic->stats.rx_dropped++;
  100.         DBG(KERN_ERR"alloc skb failed/n");
  101.         return -1;
  102.     }
  103.     skb_reserve(skb, align);                    //16bytes对齐
  104.     skb_put(skb, len);                          //移动指针,准备数据copy
  105.     if(copy_from_user(skb->data, buf, len)){    //用户空间copy数据
  106.         kfree_skb(skb);                         //失败,释放skb
  107.         DBG(KERN_INFO"copy from user failed/n");
  108.         vnic->stats.rx_dropped++;
  109.         return -1;
  110.     }
  111.     skb->dev = dev;
  112.     skb->protocol = eth_type_trans(skb, dev);   //解析以太协议
  113.     netif_rx_ni(skb);                           //提交给上层协议栈
  114.     dev->last_rx = jiffies;                     //last_rx维护
  115.     /*
  116.         设备状态维护
  117.     */
  118.     vnic->stats.rx_packets++;
  119.     vnic->stats.rx_bytes += len;
  120.     
  121.     return len;
  122. }
  123. int vnic_net_open(struct net_device *dev){
  124.     netif_start_queue(dev);         //启动队列
  125.     return 0;
  126. }
  127. int  vnic_net_stop(struct net_device *dev){
  128.     netif_stop_queue(dev);          //停止队列
  129.     return 0;
  130. }
  131. int vnic_net_tx(struct sk_buff *skb,
  132.                             struct net_device *dev){
  133.     struct vnic_struct *vnic = netdev_priv(dev);
  134.     if(skb_queue_len(&vnic->readq) >= dev->tx_queue_len){   //队列是否满
  135.         vnic->stats.tx_dropped++;                           //丢包
  136.         kfree_skb(skb);
  137.         netif_stop_queue(dev);                              //停止队列
  138.         DBG(KERN_INFO"read queue is full/n");
  139.     }else{
  140.         skb_queue_tail(&vnic->readq, skb);                  //加入收包队列,等待处理
  141.         dev->trans_start = jiffies;
  142.     }
  143.     wake_up_interruptible(&vnic->read_head);                //唤醒等待队列
  144.     DBG(KERN_DEBUG"tx queue: %d/n", skb_queue_len(&vnic->readq));
  145.     return 0;
  146. }
  147. static struct net_device_stats *vnic_net_stats(struct net_device *dev)
  148. {
  149.     struct vnic_struct *vnic = netdev_priv(dev);
  150.     return &vnic->stats;
  151. }
  152. void vnic_setup(struct net_device *dev){
  153.     struct vnic_struct *vnic = netdev_priv(dev);            //获取net_device私有数据
  154.     
  155.     ether_setup(dev);                                       //设置设备为以太网设备,定义部分以太网络的参数
  156.     /*
  157.         以下为设置网络设备的操作函数
  158.     */
  159.     dev->open = vnic_net_open;  
  160.     dev->stop = vnic_net_stop;
  161.     dev->hard_start_xmit = vnic_net_tx;
  162.     dev->get_stats = vnic_net_stats;
  163.     
  164.     random_ether_addr(dev->dev_addr);           //随机源地址
  165.     dev->tx_queue_len = READQ_SIZE;             //收包队列长度
  166.     vnic->dev = dev;                            //设置私有数据的net_device成员
  167.     memset(&vnic->stats, 0, sizeof(struct net_device_stats));
  168.     spin_lock_init(&vnic->lock);
  169.     init_waitqueue_head(&vnic->read_head);      //初始化等待队列
  170.     skb_queue_head_init(&vnic->readq);          //初始化收包队列
  171.     spin_lock(&vnic->lock);
  172.     list_add(&vnic->list, &vnic_net_list);      //将新建vnic_struct加入到设备链表
  173.     spin_unlock(&vnic->lock);
  174. }
  175. struct net_device *setup_dev(void){
  176.     struct net_device *dev;
  177.     dev = alloc_netdev(sizeof(struct vnic_struct), "vnic%d", vnic_setup);   //分配net_device,初始化函数vnic_setup
  178.     if(dev == NULL){
  179.         DBG(KERN_ERR"alloc net device failed/n");
  180.         return NULL;
  181.     }
  182.     if(register_netdev(dev) != 0){                  //注册网络设备
  183.         DBG(KERN_ERR"register net device failed/n");
  184.         return NULL;
  185.     }
  186.     
  187.     return dev;
  188. }
  189. int shutdown_dev(void){
  190.     struct vnic_struct *vnic, *next;
  191.     
  192.     list_for_each_entry_safe(vnic, next, &vnic_net_list, list){ //遍历所有vnic_struct
  193.         spin_lock(&vnic->lock);
  194.         skb_queue_purge(&vnic->readq);                          //清空收包队列
  195.         list_del(&vnic->list);                                  //将当前vnic_struct从队列中删除
  196.         unregister_netdev(vnic->dev);                           //注销网络设备
  197.         free_netdev(vnic->dev);                                 //释放网络设备
  198.         spin_unlock(&vnic->lock);
  199.     }
  200.     return 0;
  201. }
  202. static int vnic_chr_ioctl(struct inode *inode, struct file *file, 
  203.              unsigned int cmd, unsigned long arg){
  204.     int ret = 0;
  205.     struct net_device *dev;
  206.     struct vnic_struct *vnic;
  207.     
  208.     
  209.     switch(cmd){
  210.         case SETIFUP:           //建立虚拟网卡
  211.             if((dev = setup_dev()) == NULL){
  212.                 DBG(KERN_DEBUG"setup net device failed/n");
  213.                 ret = -EFAULT; 
  214.             }else{
  215.                 file->private_data = netdev_priv(dev);
  216.             }
  217.             break;
  218.         case SETIFDN:           //关闭虚拟网卡
  219.             if(shutdown_dev() == -1){
  220.                 DBG(KERN_DEBUG"shutdown net device failed/n");
  221.                 ret = -EFAULT; 
  222.             }
  223.             break;
  224.     }
  225.     
  226.     return ret;
  227. }
  228. struct file_operations vnic_ops = {
  229.     .owner = THIS_MODULE,
  230.     .llseek = no_chr_llseek,
  231.     .open = vnic_chr_open,
  232.     .release = vnic_chr_close,
  233.     .read = vnic_chr_read,
  234.     .write = vnic_chr_write,
  235.     .ioctl = vnic_chr_ioctl
  236.     
  237. };
  238. static struct miscdevice vnic_misc = {
  239.     .minor = VNIC_MINOR,        //混合设备minor号
  240.     .name = "vnic",             //设备名称
  241.     .fops = &vnic_ops           //操作函数定义
  242.     
  243. };
  244. int vnic_chr_init(void){
  245.     int ret = 0;
  246.     ret = misc_register(&vnic_misc);        //注册为混合设备,major = 10
  247.     if(ret){
  248.         DBG(KERN_INFO"misc register failed, device name:%s/n", vnic_misc.name);
  249.     }else{
  250.         DBG(KERN_INFO"misc register OK, device: %s, minor: %d/n", vnic_misc.name, vnic_misc.minor);
  251.     }
  252.     return ret;
  253.     
  254. }
  255. void vnic_chr_exit(void){
  256.     misc_deregister(&vnic_misc);        //注销混合设备
  257.     shutdown_dev();                     //关闭网络设备
  258.     DBG(KERN_INFO"misc deregister OK/n");
  259.     
  260. }
  261. MODULE_AUTHOR("wzq");
  262. MODULE_LICENSE("GPL");
  263. module_init(vnic_chr_init);
  264. module_exit(vnic_chr_exit);