1 网络传输的简介
(1)接收过程,如上图,网络上的数据包到达网卡后,网卡产生中断,然后设备驱动层收到中断后,开始进行网络包的接收,接收完之后调用一个netif_rx函数交给网络协议层(层次结构上图一),然后就是一层一层的网上传到用户空间了。
(2)发送过程,从用户空间过来的数据包,经过层层穿越之后,到达网络协议层,然后调用一个dev_queue_xmit()函数之后就不管了,剩下的交给驱动层经过处理后,使用函数hard_start_xmit()函数发送,然后硬件上网卡开始发送数据包了。
2 dm9000网卡驱动源代码分析
2.1 首先,看入口函数
1 static int __init dm9000_init(void)
2 {
3 printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);
4
5 return platform_driver_register(&dm9000_driver); /* search board and register */
6 }
这是一个平台总线的结构,注册dm9000_driver。
1 static struct platform_driver dm9000_driver = {
2 .driver = {
3 .name = "dm9000",
4 .owner = THIS_MODULE,
5 },
6 .probe = dm9000_probe,
7 .remove = dm9000_drv_remove,
8 .suspend = dm9000_drv_suspend,
9 .resume = dm9000_drv_resume,
10 };
如果平台存在与其同名的平台设备,将调用probe函数
2.2 probe函数
1 /*
2 * Search DM9000 board, allocate space and register it
3 */
4 static int
5 dm9000_probe(struct platform_device *pdev)
6 {
7 struct dm9000_plat_data *pdata = pdev->dev.platform_data;
8 struct board_info *db; /* Point a board information structure */
9 struct net_device *ndev;
10 unsigned long base;
11 int ret = 0;
12 int iosize;
13 int i;
14 u32 id_val;
15
16 #if defined(CONFIG_ARCH_S3C2410xxx)
17 unsigned int oldval_bwscon; /* 用来保存BWSCON寄存器的值 */
18 unsigned int oldval_bankcon4; /* 用来保存S3C2410_BANKCON4寄存器的值 */
19 #endif
20
21 /* Init network device */
22 ndev = alloc_etherdev(sizeof (struct board_info));
23 if (!ndev) {
24 printk("%s: could not allocate device.\n", CARDNAME);
25 return -ENOMEM;
26 }
27
28 SET_MODULE_OWNER(ndev);
29 SET_NETDEV_DEV(ndev, &pdev->dev);
30
31 PRINTK2("dm9000_probe()");
32
33 #if defined(CONFIG_ARCH_S3C2410xxx)
34 /* 设置Bank4: 总线宽度为16, 使能nWAIT。by www.100ask.net */
35 oldval_bwscon = *((volatile unsigned int *)S3C2410_BWSCON);
36 *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) \
37 | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
38
39 /* 设置BANK4的时间参数, by www.100ask.net */
40 oldval_bankcon4 = *((volatile unsigned int *)S3C2410_BANKCON4);
41 *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
42 #endif
43
44 /* setup board info structure */
45 db = (struct board_info *) ndev->priv;
46 memset(db, 0, sizeof (*db));
47
48 spin_lock_init(&db->lock);
49
50 if (pdev->num_resources < 2) {
51 ret = -ENODEV;
52 goto out;
53 } else if (pdev->num_resources == 2) {
54 base = pdev->resource[0].start;
55
56 if (!request_mem_region(base, 4, ndev->name)) {
57 ret = -EBUSY;
58 goto out;
59 }
60
61 ndev->base_addr = base;
62 ndev->irq = pdev->resource[1].start;
63 db->io_addr = (void __iomem *)base;
64 db->io_data = (void __iomem *)(base + 4);
65
66 } else {
67 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
69 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
70
71 if (db->addr_res == NULL || db->data_res == NULL ||
72 db->irq_res == NULL) {
73 printk(KERN_ERR PFX "insufficient resources\n");
74 ret = -ENOENT;
75 goto out;
76 }
77
78 i = res_size(db->addr_res);
79 db->addr_req = request_mem_region(db->addr_res->start, i,
80 pdev->name);
81
82 if (db->addr_req == NULL) {
83 printk(KERN_ERR PFX "cannot claim address reg area\n");
84 ret = -EIO;
85 goto out;
86 }
87
88 db->io_addr = ioremap(db->addr_res->start, i);
89
90 if (db->io_addr == NULL) {
91 printk(KERN_ERR "failed to ioremap address reg\n");
92 ret = -EINVAL;
93 goto out;
94 }
95
96 iosize = res_size(db->data_res);
97 db->data_req = request_mem_region(db->data_res->start, iosize,
98 pdev->name);
99
100 if (db->data_req == NULL) {
101 printk(KERN_ERR PFX "cannot claim data reg area\n");
102 ret = -EIO;
103 goto out;
104 }
105
106 db->io_data = ioremap(db->data_res->start, iosize);
107
108 if (db->io_data == NULL) {
109 printk(KERN_ERR "failed to ioremap data reg\n");
110 ret = -EINVAL;
111 goto out;
112 }
113
114 /* fill in parameters for net-dev structure */
115
116 ndev->base_addr = (unsigned long)db->io_addr;
117 ndev->irq = db->irq_res->start;
118
119 /* ensure at least we have a default set of IO routines */
120 dm9000_set_io(db, iosize);
121 }
122
123 /* check to see if anything is being over-ridden */
124 if (pdata != NULL) {
125 /* check to see if the driver wants to over-ride the
126 * default IO width */
127
128 if (pdata->flags & DM9000_PLATF_8BITONLY)
129 dm9000_set_io(db, 1);
130
131 if (pdata->flags & DM9000_PLATF_16BITONLY)
132 dm9000_set_io(db, 2);
133
134 if (pdata->flags & DM9000_PLATF_32BITONLY)
135 dm9000_set_io(db, 4);
136
137 /* check to see if there are any IO routine
138 * over-rides */
139
140 if (pdata->inblk != NULL)
141 db->inblk = pdata->inblk;
142
143 if (pdata->outblk != NULL)
144 db->outblk = pdata->outblk;
145
146 if (pdata->dumpblk != NULL)
147 db->dumpblk = pdata->dumpblk;
148 }
149
150 dm9000_reset(db);
151
152 /* try two times, DM9000 sometimes gets the first read wrong */
153 for (i = 0; i < 2; i++) {
154 id_val = ior(db, DM9000_VIDL);
155 id_val |= (u32)ior(db, DM9000_VIDH) << 8;
156 id_val |= (u32)ior(db, DM9000_PIDL) << 16;
157 id_val |= (u32)ior(db, DM9000_PIDH) << 24;
158
159 if (id_val == DM9000_ID)
160 break;
161 printk("%s: read wrong id 0x%08x\n", CARDNAME, id_val);
162 }
163
164 if (id_val != DM9000_ID) {
165 printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val);
166 goto release;
167 }
168
169 /* from this point we assume that we have found a DM9000 */
170
171 /* driver system function */
172 ether_setup(ndev);
173
174 ndev->open = &dm9000_open;
175 ndev->hard_start_xmit = &dm9000_start_xmit;
176 ndev->tx_timeout = &dm9000_timeout;
177 ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
178 ndev->stop = &dm9000_stop;
179 ndev->get_stats = &dm9000_get_stats;
180 ndev->set_multicast_list = &dm9000_hash_table;
181 #ifdef CONFIG_NET_POLL_CONTROLLER
182 ndev->poll_controller = &dm9000_poll_controller;
183 #endif
184
185 #ifdef DM9000_PROGRAM_EEPROM
186 program_eeprom(db);
187 #endif
188 db->msg_enable = NETIF_MSG_LINK;
189 db->mii.phy_id_mask = 0x1f;
190 db->mii.reg_num_mask = 0x1f;
191 db->mii.force_media = 0;
192 db->mii.full_duplex = 0;
193 db->mii.dev = ndev;
194 db->mii.mdio_read = dm9000_phy_read;
195 db->mii.mdio_write = dm9000_phy_write;
196
197 /* Read SROM content */
198 for (i = 0; i < 64; i++)
199 ((u16 *) db->srom)[i] = read_srom_word(db, i);
200
201 /* Set Node Address */
202 for (i = 0; i < 6; i++)
203 ndev->dev_addr[i] = db->srom[i];
204
205 if (!is_valid_ether_addr(ndev->dev_addr)) {
206 /* try reading from mac */
207
208 for (i = 0; i < 6; i++)
209 ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
210 }
211
212 if (!is_valid_ether_addr(ndev->dev_addr)) {
213 printk("%s: Invalid ethernet MAC address. Please "
214 "set using ifconfig\n", ndev->name);
215 #if defined(CONFIG_ARCH_S3C2410)
216 printk("Now use the default MAC address: 08:90:90:90:90:90\n");
217 ndev->dev_addr[0] = 0x08;
218 ndev->dev_addr[1] = 0x90;
219 ndev->dev_addr[2] = 0x90;
220 ndev->dev_addr[3] = 0x90;
221 ndev->dev_addr[4] = 0x90;
222 ndev->dev_addr[5] = 0x90;
223 #endif
224 }
225
226 platform_set_drvdata(pdev, ndev);
227 ret = register_netdev(ndev);
228
229 if (ret == 0) {
230 printk("%s: dm9000 at %p,%p IRQ %d MAC: ",
231 ndev->name, db->io_addr, db->io_data, ndev->irq);
232 for (i = 0; i < 5; i++)
233 printk("%02x:", ndev->dev_addr[i]);
234 printk("%02x\n", ndev->dev_addr[5]);
235 }
236 return 0;
237
238 release:
239 out:
240 printk("%s: not found (%d).\n", CARDNAME, ret);
241 #if defined(CONFIG_ARCH_S3C2410xxx)
242 /* 恢复寄存器原来的值 */
243 *((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon;
244 *((volatile unsigned int *)S3C2410_BANKCON4) = oldval_bankcon4;
245 #endif
246 dm9000_release_board(pdev, db);
247 free_netdev(ndev);
248
249 return ret;
250 }
probe函数
主要完后以下工作:
①分配一个net_device结构体(alloc_etherdev)
②定义一个单板相关信息board_info结构体
③设置net_device和board_info结构体
④使用board_info信息来初始化单板
⑤初始化网卡
⑥设置操作函数open,hard_start_xmit(发包函数),tx_timeout(超时函数),watchdog_timeo(看门狗函数),stop,get_stats,set_multicast_list
设置MAC地址
最后,注册net_device结构体
2.3 发包函数
1 /*
2 * Hardware start transmission.
3 * Send a packet to media from the upper layer.
4 */
5 static int
6 dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
7 {
8 board_info_t *db = (board_info_t *) dev->priv;
9
10 PRINTK3("dm9000_start_xmit\n");
11
12 if (db->tx_pkt_cnt > 1)
13 return 1;
14
15 netif_stop_queue(dev);
16
17 /* Disable all interrupts */
18 iow(db, DM9000_IMR, IMR_PAR);
19
20 /* Move data to DM9000 TX RAM */
21 writeb(DM9000_MWCMD, db->io_addr);
22
23 (db->outblk)(db->io_data, skb->data, skb->len);
24 db->stats.tx_bytes += skb->len;
25
26 /* TX control: First packet immediately send, second packet queue */
27 if (db->tx_pkt_cnt == 0) {
28
29 /* First Packet */
30 db->tx_pkt_cnt++;
31
32 /* Set TX length to DM9000 */
33 iow(db, DM9000_TXPLL, skb->len & 0xff);
34 iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
35
36 /* Issue TX polling command */
37 iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
38
39 dev->trans_start = jiffies; /* save the time stamp */
40
41 } else {
42 /* Second packet */
43 db->tx_pkt_cnt++;
44 db->queue_pkt_len = skb->len;
45 }
46
47 /* free this SKB */
48 dev_kfree_skb(skb);
49
50 /* Re-enable resource check */
51 if (db->tx_pkt_cnt == 1)
52 netif_wake_queue(dev);
53
54 /* Re-enable interrupt */
55 iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
56
57 return 0;
58 }
发包函数
主要完后以下工作:
1.停止该网卡的队列,把skb数据写入网卡netif_stop_queue(dev);
2.构造一个虚假的skb_buff上报
3.释放skb(dev_kfree_skb)
4.数据全部发送出去后唤醒网卡队列(netif_wake_queue)
5.更新统计信息
3 写代码
1 /*
2 * 参考 drivers\net\cs89x0.c
3 */
4
5 #include <linux/module.h>
6 #include <linux/errno.h>
7 #include <linux/netdevice.h>
8 #include <linux/etherdevice.h>
9 #include <linux/kernel.h>
10 #include <linux/types.h>
11 #include <linux/fcntl.h>
12 #include <linux/interrupt.h>
13 #include <linux/ioport.h>
14 #include <linux/in.h>
15 #include <linux/skbuff.h>
16 #include <linux/slab.h>
17 #include <linux/spinlock.h>
18 #include <linux/string.h>
19 #include <linux/init.h>
20 #include <linux/bitops.h>
21 #include <linux/delay.h>
22 #include <linux/ip.h>
23
24 #include <asm/system.h>
25 #include <asm/io.h>
26 #include <asm/irq.h>
27
28 static struct net_device *vnet_dev;
29
30 static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)
31 {
32 /* 参考LDD3 */
33 unsigned char *type;
34 struct iphdr *ih;
35 __be32 *saddr, *daddr, tmp;
36 unsigned char tmp_dev_addr[ETH_ALEN];
37 struct ethhdr *ethhdr;
38
39 struct sk_buff *rx_skb;
40
41 // 从硬件读出/保存数据
42 /* 对调"源/目的"的mac地址 */
43 ethhdr = (struct ethhdr *)skb->data;
44 memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
45 memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
46 memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);
47
48 /* 对调"源/目的"的ip地址 */
49 ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
50 saddr = &ih->saddr;
51 daddr = &ih->daddr;
52
53 tmp = *saddr;
54 *saddr = *daddr;
55 *daddr = tmp;
56
57 //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
58 //((u8 *)daddr)[2] ^= 1;
59 type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);
60 //printk("tx package type = %02x\n", *type);
61 // 修改类型, 原来0x8表示ping
62 *type = 0; /* 0表示reply */
63
64 ih->check = 0; /* and rebuild the checksum (ip needs it) */
65 ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
66
67 // 构造一个sk_buff
68 rx_skb = dev_alloc_skb(skb->len + 2);
69 skb_reserve(rx_skb, 2); /* align IP on 16B boundary */
70 memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);
71
72 /* Write metadata, and then pass to the receive level */
73 rx_skb->dev = dev;
74 rx_skb->protocol = eth_type_trans(rx_skb, dev);
75 rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
76 dev->stats.rx_packets++;
77 dev->stats.rx_bytes += skb->len;
78
79 // 提交sk_buff
80 netif_rx(rx_skb);
81 }
82
83 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)
84 {
85 static int cnt = 0;
86 printk("virt_net_send_packet cnt = %d\n", ++cnt);
87
88 /* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */
89 netif_stop_queue(dev); /* 停止该网卡的队列 */
90 /* ...... */ /* 把skb的数据写入网卡 */
91
92 /* 构造一个假的sk_buff,上报 */
93 emulator_rx_packet(skb, dev);
94
95 dev_kfree_skb (skb); /* 释放skb */
96 netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */
97
98 /* 更新统计信息 */
99 dev->stats.tx_packets++;
100 dev->stats.tx_bytes += skb->len;
101
102 return 0;
103 }
104
105
106 static int virt_net_init(void)
107 {
108 /* 1. 分配一个net_device结构体 */
109 vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);; /* alloc_etherdev */
110
111 /* 2. 设置 */
112 vnet_dev->hard_start_xmit = virt_net_send_packet;
113
114 /* 设置MAC地址 */
115 vnet_dev->dev_addr[0] = 0x08;
116 vnet_dev->dev_addr[1] = 0x89;
117 vnet_dev->dev_addr[2] = 0x89;
118 vnet_dev->dev_addr[3] = 0x89;
119 vnet_dev->dev_addr[4] = 0x89;
120 vnet_dev->dev_addr[5] = 0x11;
121
122 /* 设置下面两项才能ping通 */
123 vnet_dev->flags |= IFF_NOARP;
124 vnet_dev->features |= NETIF_F_NO_CSUM;
125
126 /* 3. 注册 */
127 //register_netdevice(vnet_dev);
128 register_netdev(vnet_dev);
129
130 return 0;
131 }
132
133 static void virt_net_exit(void)
134 {
135 unregister_netdev(vnet_dev);
136 free_netdev(vnet_dev);
137 }
138
139 module_init(virt_net_init);
140 module_exit(virt_net_exit);
141
142 MODULE_AUTHOR
143 MODULE_LICENSE("GPL");
virtnet.c