linux驱动程序之虚拟以太网设备vmeth

2019-07-12 18:19发布

Posted on 2006-10-05 15:05 倚槛追风 阅读(197) 评论(0)  编辑 收藏 引用 所属分类: 嵌入式linux,驱动程序        在《linux驱动程序之hello world》中我们编写了一个简单的能运行与linux内核态的模块,虽然它没有打印“Hello World”,我们还是称之为“hello模块”。Hello模块仅仅是一个演示,它除了打印两个字符串之外,什么也不能做了,但它具有所有可加载模块的 共性。
      今天我们对它进行扩充,使之进化为vmeth模块-虚拟的以太网设备, 这个vmeth模块向linux内核注册成为一个以太网设备,通过ifconfig命令来查看,它和其他的以太网设备如eth0没有什么区别。但这个 vmeth模块依然什么功能也没有,它仅仅将linux的TCP/IP协议栈送来的数据包打印出来(通过dmesg查看),然后将数据包free。
    为了区分这个以太网设备和普通的以太网设备,我将vmeth设备的名字命名为vmeth。当你将vmeth.ko加载到内核后,执行ifconfig -a 你将看到一个vmeth0设备,它就是vmeth模块注册的设备。OK,依次执行ifconfig vmeth0 192.168.12.12和ping 192.168.12.1,然后dmesg看看是否出现类似字样
ifconfig vmeth0 输出如下:
vmeth0    Link encap:Ethernet  HWaddr 00:00:00:00:00:00
          inet addr:192.168.12.12  Bcast:192.168.12.255  Mask:255.255.255.0
          inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

ping包后dmesg输出如下:
[ 6350.708587] vmeth receive a skb
[ 6350.708601] skb->length = 42
[ 6350.708604] [0000]ff ff ff ff ff ff 00 00 00 00 00 00 08 06 00 01
[ 6350.708617] [0010]08 00 06 04 00 01 00 00 00 00 00 00 c0 a8 0c 17
[ 6350.708629] [0020]00 00 00 00 00 00 c0 a8 0c 01

vmeth0接收到了协议栈发来的arp包,
  1 #include <linux/init.h>
  2 #include <linux/kernel.h>
  3 #include <linux/module.h>
  4 #include <linux/if.h>
  5 #include <linux/version.h>
  6 #include "vmeth.h"
  7 
  8 extern struct net_device* alloc_etherdev(int sizeof_priv);
  9 struct net_device *g_dev = NULL;
 10 
 11 /*vmeth模块初始化*/
 12 static int __init vmeth_module_init(void)
 13 {
 14     printk(KERN_DEBUG "init module/n");
 15     
 16     g_dev = alloc_etherdev(sizeof(struct vmeth_priv));
 17     if(!g_dev)
 18         goto failed;
 19     
 20     memset((struct vmeth_priv*)g_dev->priv, 0sizeof(struct vmeth_priv));
 21     strncpy(g_dev->name, VMETH_NAME, IFNAMSIZ);
 22 
 23     g_dev->init = vmeth_dev_init;
 24 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
 25     g_dev->destructor = free_netdev;
 26 #else
 27     g_dev->features |= NETIF_F_DYNALLOC;
 28 #endif
 29     /*向内核注册网络设备*/
 30     if(register_netdev(g_dev))
 31         goto register_err;
 32     
 33     return OK;
 34 register_err:
 35     kfree(g_dev);    
 36 failed:
 37     return NOK;
 38 }
 39 
 40 static void __exit vmeth_module_exit(void)
 41 {
 42     if(g_dev)
 43     {
 44         /*unregister 网络设备*/
 45         unregister_netdev(g_dev);
 46         g_dev = NULL;
 47         printk("unregister netdev/n");
 48     }
 49     printk(KERN_DEBUG "exit modules/n");
 50 }
 51 
 52 /*网络设备初始化*/
 53 static int vmeth_dev_init(struct net_device *dev)
 54 {
 55     printk(KERN_DEBUG "init net_dev/n");
 56     dev->hard_start_xmit = vmeth_send;
 57     dev->open = vmeth_open;
 58     dev->stop = vmeth_stop;
 59     return OK;
 60 }
 61 
 62 /*打开网络设备 ifconfig vmeth0 up*/
 63 static int vmeth_open(struct net_device *dev)
 64 {
 65     netif_start_queue(dev);
 66     printk(KERN_DEBUG "net device %s opened/n", dev->name);
 67     
 68     return OK;
 69 }
 70 /*关闭网络设备 ifconfig vmeth0 down*/
 71 static int vmeth_stop(struct net_device *dev)
 72 {
 73     netif_stop_queue(dev);
 74     printk(KERN_DEBUG "net device %s stopped/n", dev->name);
 75 
 76     return OK;
 77 }
 78 /*从内核接收到一个数据包*/
 79 static int vmeth_send(struct sk_buff *skb, struct net_device *dev)
 80 {
 81     printk("vmeth receive a skb/n");
 82 
 83 #ifdef DEBUG_SKB
 84     print_skb(skb);
 85 #endif    
 86     kfree_skb(skb);
 87     return 0;
 88 }
 89 
 90 #ifdef DEBUG_SKB
 91 void print_skb(struct sk_buff *skb)
 92 {
 93     int i;
 94     
 95     printk(KERN_DEBUG "skb->length = %d", skb->len);
 96     for( i = 0; i < skb->len; i++ )
 97     {
 98         if( (i&0x0f== 0)
 99         {
100             printk("/n[%04x]", i);
101         }
102         printk("%2.2x ", skb->data[i]);
103     }
104     printk("/n");
105 }
106 #endif
107 
108 module_init(vmeth_module_init);
109 module_exit(vmeth_module_exit);
110  目前vmeth0设备的物理地址还是全零,我将在后续版本中继续补充,增加vmeth的功能。
      我要下载代码vmeth.tgz(注意下载后将压缩包重命名为vmeth.tgz,使用tar -zxf vmeth.tgz命令解压),另外一定要注意修改Makefile中的KERNEL_SRC,使其指向你的内核源码。