在《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包,
我要下载代码vmeth.tgz(注意下载后将压缩包重命名为vmeth.tgz,使用tar -zxf vmeth.tgz命令解压), 另外一定要注意修改Makefile中的KERNEL_SRC,使其指向你的内核源码。
今天我们对它进行扩充,使之进化为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的功能。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
我要下载代码vmeth.tgz(注意下载后将压缩包重命名为vmeth.tgz,使用tar -zxf vmeth.tgz命令解压), 另外一定要注意修改Makefile中的KERNEL_SRC,使其指向你的内核源码。