多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > php教程 > 網(wǎng)卡驅(qū)動(dòng)設(shè)計(jì)---架構(gòu)分析加回環(huán)網(wǎng)卡驅(qū)動(dòng)設(shè)計(jì)(網(wǎng)卡驅(qū)動(dòng)上)

網(wǎng)卡驅(qū)動(dòng)設(shè)計(jì)---架構(gòu)分析加回環(huán)網(wǎng)卡驅(qū)動(dòng)設(shè)計(jì)(網(wǎng)卡驅(qū)動(dòng)上)

來源:程序員人生   發(fā)布時(shí)間:2016-06-08 09:03:12 閱讀次數(shù):3359次

網(wǎng)卡驅(qū)動(dòng)架構(gòu)分析:

1. Linux網(wǎng)絡(luò)子系統(tǒng)




2. 重要數(shù)據(jù)結(jié)構(gòu)




總結(jié)1下3個(gè)重要的數(shù)據(jù)結(jié)構(gòu):

    2.1. net_device

    2.2. net_device_ops

    2.3. sk_buff

3. 網(wǎng)卡驅(qū)動(dòng)架構(gòu)分析

CS8900.c //初期2410使用的網(wǎng)卡芯片 

3.1. 網(wǎng)卡初始化

首先找到驅(qū)動(dòng)程序的入口:

初期的驅(qū)動(dòng)入口其實(shí)不是module_init()函數(shù),而是init_module,所以找到這個(gè)函數(shù)

int __init init_module(void) { struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); struct net_local *lp; int ret = 0; #if DEBUGGING net_debug = debug; #else debug = 0; #endif if (!dev) return -ENOMEM; dev->irq = irq; dev->base_addr = io; lp = netdev_priv(dev); #if ALLOW_DMA if (use_dma) { lp->use_dma = use_dma; lp->dma = dma; lp->dmasize = dmasize; } #endif spin_lock_init(&lp->lock); /* boy, they'd better get these right */ if (!strcmp(media, "rj45")) lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; else if (!strcmp(media, "aui")) lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI; else if (!strcmp(media, "bnc")) lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2; else lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; if (duplex==⑴) lp->auto_neg_cnf = AUTO_NEG_ENABLE; if (io == 0) { printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n"); printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); ret = -EPERM; goto out; } else if (io <= 0x1ff) { ret = -ENXIO; goto out; }


第1步:分配net_device結(jié)構(gòu),

第2步:初始化net_device結(jié)構(gòu),

dev->irq = irq;//分配中斷號 dev->base_addr = io;//裝備基地址 lp = netdev_priv(dev);
第3步:

ret = cs89x0_probe1(dev, io, 1);\\這1步其實(shí)也是初始化硬件的!還有1部份是對device結(jié)構(gòu)進(jìn)行1些初始化
這個(gè)函數(shù)比較長就不貼代碼了,其中1行比較重要:

dev->netdev_ops = &net_ops; \\這個(gè)是對netdev_ops成員進(jìn)行初始化


最后1步注冊網(wǎng)卡驅(qū)動(dòng)!上圖中第2個(gè)紅色箭頭所指向的地方!

總結(jié)1下上圖:




3.2. 網(wǎng)卡數(shù)據(jù)的發(fā)送

這個(gè)結(jié)合前面的經(jīng)驗(yàn),找到網(wǎng)卡的函數(shù)操作集結(jié)構(gòu):


可以看到這個(gè)成員函數(shù)的名字叫做:net_send_packet

static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev) { struct net_local *lp = netdev_priv(dev); unsigned long flags; if (net_debug > 3) { printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); } /* keep the upload from being interrupted, since we ask the chip to start transmitting before the whole packet has been completely uploaded. */ spin_lock_irqsave(&lp->lock, flags); netif_stop_queue(dev);//1. 網(wǎng)卡驅(qū)動(dòng)在向上層發(fā)送數(shù)據(jù)的時(shí)候暫時(shí)停止接收上層發(fā)來的數(shù)據(jù) /* initiate a transmit sequence */ writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd);//2. 將skb中的數(shù)據(jù)寫入寄存器 writeword(dev->base_addr, TX_LEN_PORT, skb->len); /* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { /* * Gasp! It hasn't. But that shouldn't happen since * we're waiting for TxOk, so return 1 and requeue this packet. */ spin_unlock_irqrestore(&lp->lock, flags); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); return NETDEV_TX_BUSY; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); spin_unlock_irqrestore(&lp->lock, flags); dev->stats.tx_bytes += skb->len; dev_kfree_skb (skb);//3. 釋放skb結(jié)構(gòu) //發(fā)送數(shù)據(jù)完后,網(wǎng)卡會(huì)產(chǎn)生1個(gè)中斷 return NETDEV_TX_OK; }
產(chǎn)生1個(gè)中斷這個(gè)可以查查request_irq函數(shù),在這個(gè)函數(shù)被調(diào)用的地方可以看到這樣的1行代碼:

ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev);</span>


可以看到這里調(diào)用了net_initerupt函數(shù),網(wǎng)卡發(fā)送和接收中斷!


1個(gè)是發(fā)送中斷,1個(gè)是接收中斷,

netif_wake_queue(dev);/* Inform upper layers. */   // 這行代碼表示在發(fā)送中斷處理進(jìn)程中,通知上層協(xié)議,可以再次向網(wǎng)卡傳輸數(shù)據(jù)。


3.3. 網(wǎng)卡數(shù)據(jù)的接收

網(wǎng)卡數(shù)據(jù)的接收入口是在中斷中完成的,這個(gè)是從中斷函數(shù)中可以看到net_interrupt


接收中斷處理函數(shù)net_rx(dev)

/* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct net_device *dev) { struct sk_buff *skb; int status, length; int ioaddr = dev->base_addr; status = readword(ioaddr, RX_FRAME_PORT);//讀取寄存器,網(wǎng)卡接收狀態(tài) length = readword(ioaddr, RX_FRAME_PORT);//網(wǎng)卡接收字節(jié)長度 if ((status & RX_OK) == 0) { count_rx_errors(status, dev); return; } /* Malloc up new buffer. */ skb = dev_alloc_skb(length + 2);//分配skb結(jié)構(gòu) +2字節(jié)空間是為頭預(yù)留的 if (skb == NULL) { #if 0 /* Again, this seems a cruel thing to do */ printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); #endif dev->stats.rx_dropped++; return; } skb_reserve(skb, 2); /* longword align L3 header */ readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);//將收到的數(shù)據(jù)填充入skb if (length & 1) skb->data[length⑴] = readword(ioaddr, RX_FRAME_PORT); if (net_debug > 3) { printk( "%s: received %d byte packet of type %x\n", dev->name, length, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb);//將skb提交到協(xié)議棧 dev->stats.rx_packets++; dev->stats.rx_bytes += length; }


回環(huán)網(wǎng)卡驅(qū)動(dòng)設(shè)計(jì):


使用ifocnfig,可以看到除eth0還有1個(gè)l0, eth0代表的是1個(gè)物理網(wǎng)卡,l0代表的就是回環(huán)網(wǎng)卡,從上面的打印信息可以看到l0的IP地址是127.0.0.1,可以看到當(dāng)ping 127.0.0.x的時(shí)候能ping通,其實(shí)l0就是網(wǎng)卡的tx和rx在軟件層的短接!所以才叫做回環(huán)網(wǎng)卡!

其實(shí)內(nèi)核代碼中也能夠找到回環(huán)網(wǎng)卡的驅(qū)動(dòng)!Lookback.c

這個(gè)文件中的代碼部份其實(shí)不是內(nèi)核模塊,而是由其它部份的調(diào)用的!

刪掉內(nèi)核代碼中的原本的loopback.c,結(jié)合上面的的分析和原有源碼的分析重寫編寫loopback.c,

#include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/if_ether.h> /* For the statistics structure. */ unsigned long bytes = 0; unsigned long packets = 0;//skb包 static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)//數(shù)據(jù)發(fā)送 { skb->protocol = eth_type_trans(skb,dev);//表明skb包的協(xié)議 以太網(wǎng)協(xié)議 bytes += skb->len;//發(fā)送的數(shù)據(jù)量 packets++; //發(fā)送的數(shù)據(jù)包也要加1 netif_rx(skb);//將skb向回送, 回環(huán)網(wǎng)卡驅(qū)動(dòng)就是這實(shí)現(xiàn)的,這是很關(guān)鍵的1步 return 0; } static struct net_device_stats *loopback_get_stats(struct net_device *dev)//獲得網(wǎng)卡狀態(tài) { struct net_device_stats *stats = &dev->stats;//首先把state這個(gè)成員取出來 stats->rx_packets = packets;//表示網(wǎng)卡收到了多少個(gè)包 stats->tx_packets = packets;//表示網(wǎng)卡發(fā)送了多少個(gè)包 stats->rx_bytes = bytes;//表示網(wǎng)卡接收到了多少個(gè)字節(jié) stats->tx_bytes = bytes; return stats;//返回狀態(tài) } static const struct net_device_ops loopback_ops = {//定義1個(gè)net_device_ops 結(jié)構(gòu) .ndo_start_xmit= loopback_xmit,//發(fā)送指針 .ndo_get_stats = loopback_get_stats,//獲得網(wǎng)卡狀態(tài)的函數(shù) }; static void loopback_setup(struct net_device *dev)//初始化設(shè)置操作 { dev->mtu = (16 * 1024) + 20 + 20 + 12;//網(wǎng)卡最大接收包的尺寸:16K + TCP頭 + IP頭 + 以太網(wǎng)頭 dev->flags = IFF_LOOPBACK;//回環(huán)網(wǎng)卡專有標(biāo)志 這是1個(gè)宏內(nèi)核代碼可查 dev->header_ops = ð_header_ops;//這個(gè)是網(wǎng)絡(luò)包的函數(shù)操作集,內(nèi)核可以看這個(gè)成員的數(shù)據(jù)結(jié)構(gòu) dev->netdev_ops = &loopback_ops;//網(wǎng)卡所支持操作的集合 } static __net_init int loopback_net_init(struct net *net) { struct net_device *dev; int err; err = -ENOMEM; dev = alloc_netdev(0, "lo", loopback_setup);//分配1個(gè)net_device結(jié)構(gòu),loopback為1個(gè)初始化函數(shù) if (!dev) goto out; err = register_netdev(dev);//注冊網(wǎng)卡驅(qū)動(dòng)程序 if (err) goto out_free_netdev; net->loopback_dev = dev; return 0; out_free_netdev: free_netdev(dev); out: if (net == &init_net) panic("loopback: Failed to register netdevice: %d\n", err); return err; } static __net_exit void loopback_net_exit(struct net *net) { struct net_device *dev = net->loopback_dev; unregister_netdev(dev);//注銷網(wǎng)卡驅(qū)動(dòng)程序 } /* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, .exit = loopback_net_exit, }; </span>

保存,然后重新編譯內(nèi)核,下載到開發(fā)板看運(yùn)行效果!


上面的回環(huán)網(wǎng)卡驅(qū)動(dòng)有點(diǎn)問題,ping不同!

這是能ping通的內(nèi)核自帶的源碼:

#include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/string.h> #include <linux/socket.h> #include <linux/errno.h> #include <linux/fcntl.h> #include <linux/in.h> #include <linux/init.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/ethtool.h> #include <net/sock.h> #include <net/checksum.h> #include <linux/if_ether.h> /* For the statistics structure. */ #include <linux/if_arp.h> /* For ARPHRD_ETHER */ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/percpu.h> #include <net/net_namespace.h> #include <linux/u64_stats_sync.h> struct pcpu_lstats { u64 packets; u64 bytes; struct u64_stats_sync syncp; }; /* * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcpu_lstats *lb_stats; int len; skb_orphan(skb); skb->protocol = eth_type_trans(skb, dev); /* it's OK to use per_cpu_ptr() because BHs are off */ lb_stats = this_cpu_ptr(dev->lstats); len = skb->len; if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { u64_stats_update_begin(&lb_stats->syncp); lb_stats->bytes += len; lb_stats->packets++; u64_stats_update_end(&lb_stats->syncp); } return NETDEV_TX_OK; } static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { u64 bytes = 0; u64 packets = 0; int i; for_each_possible_cpu(i) { const struct pcpu_lstats *lb_stats; u64 tbytes, tpackets; unsigned int start; lb_stats = per_cpu_ptr(dev->lstats, i); do { start = u64_stats_fetch_begin(&lb_stats->syncp); tbytes = lb_stats->bytes; tpackets = lb_stats->packets; } while (u64_stats_fetch_retry(&lb_stats->syncp, start)); bytes += tbytes; packets += tpackets; } stats->rx_packets = packets; stats->tx_packets = packets; stats->rx_bytes = bytes; stats->tx_bytes = bytes; return stats; } static u32 always_on(struct net_device *dev) { return 1; } static const struct ethtool_ops loopback_ethtool_ops = { .get_link = always_on, }; static int loopback_dev_init(struct net_device *dev) { dev->lstats = alloc_percpu(struct pcpu_lstats); if (!dev->lstats) return -ENOMEM; return 0; } static void loopback_dev_free(struct net_device *dev) { free_percpu(dev->lstats); free_netdev(dev); } static const struct net_device_ops loopback_ops = { .ndo_init = loopback_dev_init, .ndo_start_xmit= loopback_xmit, .ndo_get_stats64 = loopback_get_stats64, }; /* * The loopback device is special. There is only one instance * per network namespace. */ static void loopback_setup(struct net_device *dev) { dev->mtu = (16 * 1024) + 20 + 20 + 12; dev->hard_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->hw_features = NETIF_F_ALL_TSO | NETIF_F_UFO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | NETIF_F_UFO | NETIF_F_NO_CSUM | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL | NETIF_F_VLAN_CHALLENGED | NETIF_F_LOOPBACK; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; dev->netdev_ops = &loopback_ops; dev->destructor = loopback_dev_free; } /* Setup and register the loopback device. */ static __net_init int loopback_net_init(struct net *net) { struct net_device *dev; int err; err = -ENOMEM; dev = alloc_netdev(0, "lo", loopback_setup); if (!dev) goto out; dev_net_set(dev, net); err = register_netdev(dev); if (err) goto out_free_netdev; net->loopback_dev = dev; return 0; out_free_netdev: free_netdev(dev); out: if (net_eq(net, &init_net)) panic("loopback: Failed to register netdevice: %d\n", err); return err; } /* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, };

自己將兩份源碼對比著看了,暫時(shí)還沒找出緣由,這里先上1張毛病的截圖和我認(rèn)為出錯(cuò)的緣由


在使用ifconfig命令的時(shí)候,發(fā)現(xiàn)RX, TX, 竟然都有packets網(wǎng)絡(luò)包數(shù)據(jù)傳輸,當(dāng)ping 127.0.0.x的時(shí)候會(huì)1直阻塞在哪里,說明問題應(yīng)當(dāng)在初始化參數(shù)設(shè)置的部份!這里有數(shù)據(jù)包發(fā)送但是沒有接收到數(shù)據(jù)包!說明數(shù)據(jù)接收部份,也就是回環(huán)發(fā)送部份有問題!這里暫時(shí)先擱1下,后邊在殺個(gè)回馬槍來深入研究1下!


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 1314成人网 | 亚洲黄色片网站 | 另类二区 | 日本欧美韩国专区 | 女人笫一次一级毛片 | 国产成人精品一区二区不卡 | 美女享受黑人的巨茎 | 精品91| 国产日产欧美精品一区二区三区 | 日本道色综合久久影院 | 中日韩欧美在线观看 | 国产亚洲精品久久久久久午夜 | 国产片在线观看播放 | 中文字幕无线精品乱码一区 | 亚洲精品人成无码中文毛片 | 亚洲欧美综合另类 | 精品国产日韩久久亚洲 | 高清国产性色视频在线 | 欧美xart系列高清在线视频 | 欧美日韩中文一区二区三区 | 亚洲m男在线中文字幕 | 美国伊人 | 亚洲国产第一区二区三区 | 亚洲网址| 高清一级做a爱免费视 | free性欧美黑人 | 午夜免费在线观看 | 99久久精品国产高清一区二区 | 综合色图 | 国产成人精品日本亚洲18图 | 欧美激情视频一区二区 | 亚洲天堂二区 | 久久riav| 国产成人欧美 | 欧美日韩一区二区三区视频 | 欧美日本免费 | 欧美孕妇与黑人巨交 | 福利视频一二区 | 亚洲精品国产综合久久一线 | 亚洲欧美综合精品成 | 亚洲一区二区三区不卡视频 |