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, 0, sizeof(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,使其指向你的内核源码。