日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

發布時間:2025/7/25 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文分析基于Linux Kernel 1.2.13

原創作品,轉載請標明http://blog.csdn.net/yming0221/article/details/7497260

更多請看專欄,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:閆明

注:標題中的”(上)“,”(下)“表示分析過程基于數據包的傳遞方向:”(上)“表示分析是從底層向上分析、”(下)“表示分析是從上向下分析。


經過前面兩篇博文的分析,已經對Linux的內核網絡棧的結構有了一個模糊的認識,這里我們開始從底層開始詳細分析Linux內核網絡棧的實現。由于這是早期版本,代碼的層次隔離做的還不是很好,這里說是從底層分析,但是不免會牽扯上層或下層的函數,許多關鍵代碼都在驅動的文件夾下。

我們首先有第一篇博文中知道在網絡棧初始化的時候在net/socket.c中的函數sock_init()函數中當proto_init()完成后會執行dev_init()來進行網絡設備模塊的初始化。

首先說明一下,在drivers/net/space.c中定義了設備首節點地址dev_base,其實際上是回環設備的地址。

[cpp]?view plaincopy
  • struct?device?loopback_dev?=?{??
  • ????"lo",???????????/*?Software?Loopback?interface??????*/??
  • ????0x0,????????????/*?recv?memory?end??????????*/??
  • ????0x0,????????????/*?recv?memory?start????????????*/??
  • ????0x0,????????????/*?memory?end???????????????*/??
  • ????0x0,????????????/*?memory?start?????????????*/??
  • ????0,??????????/*?base?I/O?address?????????*/??
  • ????0,??????????/*?IRQ??????????????????*/??
  • ????0,?0,?0,????????/*?flags????????????????*/??
  • ????NEXT_DEV,???????/*?next?device??????????????*/??
  • ????loopback_init???????/*?loopback_init?should?set?up?the?rest?*/??
  • };??
  • ??
  • struct?device?*dev_base?=?&loopback_dev;??
  • 而NEXT_DEV宏定義即定義了下一個網絡設備的地址,這樣可以把設備串成鏈。

    附網絡設備的定義(include/linux/netdevice.h)如下:

    [cpp]?view plaincopy
  • /*?
  • ?*?The?DEVICE?structure.?
  • ?*?Actually,?this?whole?structure?is?a?big?mistake.??It?mixes?I/O?
  • ?*?data?with?strictly?"high-level"?data,?and?it?has?to?know?about?
  • ?*?almost?every?data?structure?used?in?the?INET?module.???
  • ?*/??
  • struct?device???
  • {??
  • ??
  • ??/*?
  • ???*?This?is?the?first?field?of?the?"visible"?part?of?this?structure?
  • ???*?(i.e.?as?seen?by?users?in?the?"Space.c"?file).??It?is?the?name?
  • ???*?the?interface.?
  • ???*/??
  • ??char????????????*name;??
  • ??
  • ??/*?I/O?specific?fields?-?FIXME:?Merge?these?and?struct?ifmap?into?one?*/??
  • ??unsigned?long???????rmem_end;?????/*?shmem?"recv"?end?*/??
  • ??unsigned?long???????rmem_start;???????/*?shmem?"recv"?start???*/??
  • ??unsigned?long???????mem_end;??????/*?sahared?mem?end??*/??
  • ??unsigned?long???????mem_start;????????/*?shared?mem?start?*/??
  • ??unsigned?long???????base_addr;????????/*?device?I/O?address???*/??
  • ??unsigned?char???????irq;??????????/*?device?IRQ?number????*/??
  • ??
  • ??/*?Low-level?status?flags.?*/??
  • ??volatile?unsigned?char??start,????????/*?start?an?operation???*/??
  • ??????????????????????????tbusy,????????/*?transmitter?busy?*/??
  • ??????????????????????????interrupt;????????/*?interrupt?arrived????*/??
  • ??
  • ??struct?device???????*next;??
  • ??
  • ??/*?The?device?initialization?function.?Called?only?once.?*/??
  • ??int?????????????(*init)(struct?device?*dev);??
  • ??
  • ??/*?Some?hardware?also?needs?these?fields,?but?they?are?not?part?of?the?
  • ?????usual?set?specified?in?Space.c.?*/??
  • ??unsigned?char???????if_port;??????/*?Selectable?AUI,?TP,..*/??
  • ??unsigned?char???????dma;??????????/*?DMA?channel??????*/??
  • ??
  • ??struct?enet_statistics*?(*get_stats)(struct?device?*dev);??
  • ??
  • ??/*?
  • ???*?This?marks?the?end?of?the?"visible"?part?of?the?structure.?All?
  • ???*?fields?hereafter?are?internal?to?the?system,?and?may?change?at?
  • ???*?will?(read:?may?be?cleaned?up?at?will).?
  • ???*/??
  • ??
  • ??/*?These?may?be?needed?for?future?network-power-down?code.?*/??
  • ??unsigned?long???????trans_start;??/*?Time?(in?jiffies)?of?last?Tx?*/??
  • ??unsigned?long???????last_rx;??/*?Time?of?last?Rx??????*/??
  • ??
  • ??unsigned?short??????flags;????/*?interface?flags?(a?la?BSD)???*/??
  • ??unsigned?short??????family;???/*?address?family?ID?(AF_INET)??*/??
  • ??unsigned?short??????metric;???/*?routing?metric?(not?used)????*/??
  • ??unsigned?short??????mtu;??????/*?interface?MTU?value??????*/??
  • ??unsigned?short??????type;?????/*?interface?hardware?type??*/??
  • ??unsigned?short??????hard_header_len;??/*?hardware?hdr?length??*/??
  • ??void????????????*priv;????/*?pointer?to?private?data??*/??
  • ??
  • ??/*?Interface?address?info.?*/??
  • ??unsigned?char???????broadcast[MAX_ADDR_LEN];??/*?hw?bcast?add?*/??
  • ??unsigned?char???????dev_addr[MAX_ADDR_LEN];???/*?hw?address???*/??
  • ??unsigned?char???????addr_len;?/*?hardware?address?length??*/??
  • ??unsigned?long???????pa_addr;??/*?protocol?address?????*/??
  • ??unsigned?long???????pa_brdaddr;???/*?protocol?broadcast?addr??*/??
  • ??unsigned?long???????pa_dstaddr;???/*?protocol?P-P?other?side?addr?*/??
  • ??unsigned?long???????pa_mask;??/*?protocol?netmask?????*/??
  • ??unsigned?short??????pa_alen;??/*?protocol?address?length??*/??
  • ??
  • ??struct?dev_mc_list?????*mc_list;??/*?Multicast?mac?addresses??*/??
  • ??int????????????mc_count;??/*?Number?of?installed?mcasts???*/??
  • ????
  • ??struct?ip_mc_list??*ip_mc_list;???/*?IP?multicast?filter?chain????*/??
  • ??????
  • ??/*?For?load?balancing?driver?pair?support?*/??
  • ????
  • ??unsigned?long????????pkt_queue;???/*?Packets?queued?*/??
  • ??struct?device???????*slave;???/*?Slave?device?*/??
  • ????
  • ??
  • ??/*?Pointer?to?the?interface?buffers.?*/??
  • ??struct?sk_buff_head?????buffs[DEV_NUMBUFFS];??
  • ??
  • ??/*?Pointers?to?interface?service?routines.?*/??
  • ??int?????????????(*open)(struct?device?*dev);??
  • ??int?????????????(*stop)(struct?device?*dev);??
  • ??int?????????????(*hard_start_xmit)?(struct?sk_buff?*skb,??
  • ??????????????????????????struct?device?*dev);??
  • ??int?????????????(*hard_header)?(unsigned?char?*buff,??
  • ??????????????????????struct?device?*dev,??
  • ??????????????????????unsigned?short?type,??
  • ??????????????????????void?*daddr,??
  • ??????????????????????void?*saddr,??
  • ??????????????????????unsigned?len,??
  • ??????????????????????struct?sk_buff?*skb);??
  • ??int?????????????(*rebuild_header)(void?*eth,?struct?device?*dev,??
  • ????????????????unsigned?long?raddr,?struct?sk_buff?*skb);??
  • ??unsigned?short??????(*type_trans)?(struct?sk_buff?*skb,??
  • ?????????????????????struct?device?*dev);??
  • #define?HAVE_MULTICAST?????????????
  • ??void????????????(*set_multicast_list)(struct?device?*dev,??
  • ?????????????????????int?num_addrs,?void?*addrs);??
  • #define?HAVE_SET_MAC_ADDR??????????
  • ??int?????????????(*set_mac_address)(struct?device?*dev,?void?*addr);??
  • #define?HAVE_PRIVATE_IOCTL??
  • ??int?????????????(*do_ioctl)(struct?device?*dev,?struct?ifreq?*ifr,?int?cmd);??
  • #define?HAVE_SET_CONFIG??
  • ??int?????????????(*set_config)(struct?device?*dev,?struct?ifmap?*map);??
  • ????
  • };??

  • dev_init()網絡設備的初始化函數如下:

    [cpp]?view plaincopy
  • /*?
  • ?*??Initialize?the?DEV?module.?At?boot?time?this?walks?the?device?list?and?
  • ?*??unhooks?any?devices?that?fail?to?initialise?(normally?hardware?not??
  • ?*??present)?and?leaves?us?with?a?valid?list?of?present?and?active?devices.?
  • ?*?
  • ?*??The?PCMCIA?code?may?need?to?change?this?a?little,?and?add?a?pair?
  • ?*??of?register_inet_device()?unregister_inet_device()?calls.?This?will?be?
  • ?*??needed?for?ethernet?as?modules?support.?
  • ?*/??
  • ???
  • void?dev_init(void)??
  • {??
  • ????struct?device?*dev,?*dev2;??
  • ??
  • ????/*?
  • ?????*??Add?the?devices.?
  • ?????*??If?the?call?to?dev->init?fails,?the?dev?is?removed?
  • ?????*??from?the?chain?disconnecting?the?device?until?the?
  • ?????*??next?reboot.?
  • ?????*/??
  • ???????
  • ????dev2?=?NULL;??
  • ????for?(dev?=?dev_base;?dev?!=?NULL;?dev=dev->next)?//循環移除設備由璞傅絛ev_base指向的網絡設備鏈表??
  • ????{??
  • ????????if?(dev->init?&&?dev->init(dev))?//如果設備有初始化函數并且初始化失敗,則從鏈表摘除設備(init()函數成功返回0)??
  • ????????{??
  • ????????????/*?
  • ?????????????*??It?failed?to?come?up.?Unhook?it.這個函數還挺有技巧性的,從默認配置的設備中掃描不存在的設備,將其移除?
  • ?????????????*/??
  • ???????????????
  • ????????????if?(dev2?==?NULL)???
  • ????????????????dev_base?=?dev->next;??
  • ????????????else???
  • ????????????????dev2->next?=?dev->next;??
  • ????????}???
  • ????????else??
  • ????????{??
  • ????????????dev2?=?dev;??
  • ????????}??
  • ????}??
  • }??
  • 這里我們看一下dev_base這個隊列是如何定義的,這里我們僅僅看eth網卡的定義方式即可

    [cpp]?view plaincopy
  • /*?"eth0"?defaults?to?autoprobe?(==?0),?other?use?a?base?of?0xffe0?(==?-0x20),?
  • ???which?means?"don't?probe".??These?entries?exist?to?only?to?provide?empty?
  • ???slots?which?may?be?enabled?at?boot-time.?*/??
  • ??
  • static?struct?device?eth3_dev?=?{??
  • ????"eth3",?0,0,0,0,0xffe0?/*?I/O?base*/,?0,0,0,0,?NEXT_DEV,?ethif_probe?};??
  • static?struct?device?eth2_dev?=?{??
  • ????"eth2",?0,0,0,0,0xffe0?/*?I/O?base*/,?0,0,0,0,?eth3_dev,?ethif_probe?};??
  • static?struct?device?eth1_dev?=?{??
  • ????"eth1",?0,0,0,0,0xffe0?/*?I/O?base*/,?0,0,0,0,?eth2_dev,?ethif_probe?};??
  • ??
  • static?struct?device?eth0_dev?=?{??
  • ????"eth0",?0,?0,?0,?0,?ETH0_ADDR,?ETH0_IRQ,?0,?0,?0,?eth1_dev,?ethif_probe?};??
  • ??
  • #???undef?NEXT_DEV??
  • #???define?NEXT_DEV?(eth0_dev)??

  • 可以看出eth系列網卡設備的init函數定義為ethif_probe(),該函數會調用具體網卡的探測函數,我們還是以?NS8390 ethernet網卡為例來分析,該網卡的驅動實現文件為drivers/net/ne.c

    ethif_probe()函數會調用函數ne_probe()探測函數,而該函數對設備地址進行檢查后調用ne_probe1()函數,具體工作有ne_probe1()函數完成。


    函數如下:

    [cpp]?view plaincopy
  • static?int?ne_probe1(struct?device?*dev,?int?ioaddr)??
  • {??
  • .....................//合法性檢查??
  • /*?Fixup?for?users?that?don't?know?that?IRQ?2?is?really?IRQ?9,?
  • ???????or?don't?know?which?one?to?set.?*/??
  • ????dev->irq?=?9;//設置中斷類型號??
  • ??????
  • ????/*?Snarf?the?interrupt?now.??There's?no?point?in?waiting?since?we?cannot?
  • ???????share?and?the?board?will?usually?be?enabled.?*/??
  • ????{??
  • ????int?irqval?=?request_irq?(dev->irq,?ei_interrupt,?0,?wordlength==2???"ne2000":"ne1000");//注冊申請中斷,中斷處理函數為ei_interrupt??
  • ????if?(irqval)?{??
  • ????????printk?("?unable?to?get?IRQ?%d?(irqval=%d).\n",?dev->irq,?irqval);??
  • ????????return?EAGAIN;??
  • ????}??
  • ????}??
  • ??
  • ????dev->base_addr?=?ioaddr;??
  • ??
  • ????request_region(ioaddr,?NE_IO_EXTENT,?wordlength==2???"ne2000":"ne1000");//申請內存空間??
  • ??
  • ????for(i?=?0;?i?<?ETHER_ADDR_LEN;?i++)??
  • ????dev->dev_addr[i]?=?SA_prom[i];??
  • ??
  • ????ethdev_init(dev);//調用函數對dev設備結構體進行初始化??
  • ????printk("\n%s:?%s?found?at?%#x,?using?IRQ?%d.\n",??
  • ???????dev->name,?name,?ioaddr,?dev->irq);??
  • ??
  • ????if?(ei_debug?>?0)??
  • ????printk(version);??
  • ??
  • ????ei_status.name?=?name;??
  • ????ei_status.tx_start_page?=?start_page;??
  • ????ei_status.stop_page?=?stop_page;??
  • ????ei_status.word16?=?(wordlength?==?2);??
  • ??
  • ????ei_status.rx_start_page?=?start_page?+?TX_PAGES;??
  • #ifdef?PACKETBUF_MEMSIZE??
  • ????/*?Allow?the?packet?buffer?size?to?be?overridden?by?know-it-alls.?*/??
  • ????ei_status.stop_page?=?ei_status.tx_start_page?+?PACKETBUF_MEMSIZE;??
  • #endif??
  • ??
  • ????ei_status.reset_8390?=?&ne_reset_8390;??
  • ????ei_status.block_input?=?&ne_block_input;??
  • ????ei_status.block_output?=?&ne_block_output;??
  • ????NS8390_init(dev,?0);//配置網卡中的寄存器等到默認狀態??
  • ????return?0;??
  • }??
  • 初始化函數ethdev_init()在文件drivers/net/8390.c中。如下:

    [cpp]?view plaincopy
  • /*?Initialize?the?rest?of?the?8390?device?structure.?*/??
  • int?ethdev_init(struct?device?*dev)??
  • {??
  • ????if?(ei_debug?>?1)??
  • ????????printk(version);??
  • ??????
  • ????if?(dev->priv?==?NULL)?{//申請私有空間存儲具體網卡的結構體信息??
  • ????????struct?ei_device?*ei_local;//8390網卡設備的結構體??
  • ??????????
  • ????????dev->priv?=?kmalloc(sizeof(struct?ei_device),?GFP_KERNEL);//申請內核內存空間??
  • ????????memset(dev->priv,?0,?sizeof(struct?ei_device));??
  • ????????ei_local?=?(struct?ei_device?*)dev->priv;??
  • #ifndef?NO_PINGPONG??
  • ????????ei_local->pingpong?=?1;??
  • #endif??
  • ????}??
  • ??????
  • ????/*?The?open?call?may?be?overridden?by?the?card-specific?code.?*/??
  • ????if?(dev->open?==?NULL)??
  • ????????dev->open?=?&ei_open;//設備的打開函數??
  • ????/*?We?should?have?a?dev->stop?entry?also.?*/??
  • ????dev->hard_start_xmit?=?&ei_start_xmit;//設備的發送函數,定義在8390.c中??
  • ????dev->get_stats???=?get_stats;??
  • #ifdef?HAVE_MULTICAST??
  • ????dev->set_multicast_list?=?&set_multicast_list;??
  • #endif??
  • ??
  • ????ether_setup(dev);//進一步調用函數設置dev設備結構體??
  • ??????????
  • ????return?0;??
  • }??
  • ether_setup()函數的實現如下:

    [cpp]?view plaincopy
  • void?ether_setup(struct?device?*dev)??
  • {??
  • ????int?i;??
  • ????/*?Fill?in?the?fields?of?the?device?structure?with?ethernet-generic?values.?
  • ???????This?should?be?in?a?common?file?instead?of?per-driver.??*/??
  • ????for?(i?=?0;?i?<?DEV_NUMBUFFS;?i++)??
  • ????????skb_queue_head_init(&dev->buffs[i]);//緩沖隊列初始化??
  • ??
  • ????/*?register?boot-defined?"eth"?devices?*/??
  • ????if?(dev->name?&&?(strncmp(dev->name,?"eth",?3)?==?0))?{//定義eth網卡的名稱??
  • ????????i?=?simple_strtoul(dev->name?+?3,?NULL,?0);??
  • ????????if?(ethdev_index[i]?==?NULL)?{??
  • ????????????ethdev_index[i]?=?dev;??
  • ????????}??
  • ????????else?if?(dev?!=?ethdev_index[i])?{??
  • ????????????/*?Really?shouldn't?happen!?*/??
  • ????????????printk("ether_setup:?Ouch!?Someone?else?took?%s\n",??
  • ????????????????dev->name);??
  • ????????}??
  • ????}??
  • ??
  • ????dev->hard_header?=?eth_header;//該函數的作用是創建鏈路層首部,定義在eth.c中??
  • ????dev->rebuild_header?=?eth_rebuild_header;//該函數的作用是重建鏈路層首部,用于ARP協議??
  • ????dev->type_trans?=?eth_type_trans;??
  • ??
  • ????dev->type????????=?ARPHRD_ETHER;??
  • ????dev->hard_header_len?=?ETH_HLEN;??
  • ????dev->mtu?????=?1500;?/*?eth_mtu?*/??
  • ????dev->addr_len????=?ETH_ALEN;??
  • ????for?(i?=?0;?i?<?ETH_ALEN;?i++)?{??
  • ????????dev->broadcast[i]=0xff;??
  • ????}??
  • ??
  • ????/*?New-style?flags.?*/??
  • ????dev->flags???????=?IFF_BROADCAST|IFF_MULTICAST;??
  • ????dev->family??????=?AF_INET;??
  • ????dev->pa_addr?=?0;??
  • ????dev->pa_brdaddr?=?0;??
  • ????dev->pa_mask?=?0;??
  • ????dev->pa_alen?=?sizeof(unsigned?long);??
  • }??

  • 這樣,網絡設備的初始化工作就完成了。

    在drivers/net/8390.c中實現了該網卡的設備的基本操作函數,



    設備的打開函數ei_open()比較簡單,下面列出該設備的發送和接收函數,在這里不做具體的分析,如果想更多了解請點擊前面分析過的DM9000網卡驅動,下面給出鏈接:

  • ARM-Linux驅動--DM9000網卡驅動分析(一)
  • ARM-Linux驅動--DM9000網卡驅動分析(二)
  • ARM-Linux驅動--DM9000網卡驅動分析(三)
  • ARM-Linux驅動--DM9000網卡驅動分析(四)
  • 其基本結構是一致的。

    ei_start_xmit()

    [cpp]?view plaincopy
  • static?int?ei_start_xmit(struct?sk_buff?*skb,?struct?device?*dev)??
  • {??
  • ????int?e8390_base?=?dev->base_addr;??
  • ????struct?ei_device?*ei_local?=?(struct?ei_device?*)?dev->priv;??
  • ????int?length,?send_length;??
  • ????unsigned?long?flags;??
  • ??????
  • /*?
  • ?*??We?normally?shouldn't?be?called?if?dev->tbusy?is?set,?but?the?
  • ?*??existing?code?does?anyway.?If?it?has?been?too?long?since?the?
  • ?*??last?Tx,?we?assume?the?board?has?died?and?kick?it.?
  • ?*/??
  • ???
  • ????if?(dev->tbusy)?{????/*?Do?timeouts,?just?like?the?8003?driver.?*/??
  • ????????int?txsr?=?inb(e8390_base+EN0_TSR),?isr;??
  • ????????int?tickssofar?=?jiffies?-?dev->trans_start;??
  • ????????if?(tickssofar?<?TX_TIMEOUT?||???(tickssofar?<?(TX_TIMEOUT+5)?&&?!?(txsr?&?ENTSR_PTX)))?{??
  • ????????????return?1;??
  • ????????}??
  • ????????isr?=?inb(e8390_base+EN0_ISR);??
  • ????????if?(dev->start?==?0)?{??
  • ????????????printk("%s:?xmit?on?stopped?card\n",?dev->name);??
  • ????????????return?1;??
  • ????????}??
  • ????????printk(KERN_DEBUG?"%s:?transmit?timed?out,?TX?status?%#2x,?ISR?%#2x.\n",??
  • ???????????????dev->name,?txsr,?isr);??
  • ????????/*?Does?the?8390?thinks?it?has?posted?an?interrupt??*/??
  • ????????if?(isr)??
  • ????????????printk(KERN_DEBUG?"%s:?Possible?IRQ?conflict?on?IRQ%d?\n",?dev->name,?dev->irq);??
  • ????????else?{??
  • ????????????/*?The?8390?probably?hasn't?gotten?on?the?cable?yet.?*/??
  • ????????????printk(KERN_DEBUG?"%s:?Possible?network?cable?problem?\n",?dev->name);??
  • ????????????if(ei_local->stat.tx_packets==0)??
  • ????????????????ei_local->interface_num?^=?1;????/*?Try?a?different?xcvr.??*/??
  • ????????}??
  • ????????/*?Try?to?restart?the?card.??Perhaps?the?user?has?fixed?something.?*/??
  • ????????ei_reset_8390(dev);??
  • ????????NS8390_init(dev,?1);??
  • ????????dev->trans_start?=?jiffies;??
  • ????}??
  • ??????
  • ????/*?Sending?a?NULL?skb?means?some?higher?layer?thinks?we've?missed?an?
  • ???????tx-done?interrupt.?Caution:?dev_tint()?handles?the?cli()/sti()?
  • ???????itself.?*/??
  • ????if?(skb?==?NULL)?{??
  • ????????dev_tint(dev);??
  • ????????return?0;??
  • ????}??
  • ??????
  • ????length?=?skb->len;??
  • ????if?(skb->len?<=?0)??
  • ????????return?0;??
  • ??
  • ????save_flags(flags);??
  • ????cli();??
  • ??
  • ????/*?Block?a?timer-based?transmit?from?overlapping.?*/??
  • ????if?((set_bit(0,?(void*)&dev->tbusy)?!=?0)?||?ei_local->irqlock)?{??
  • ????printk("%s:?Tx?access?conflict.?irq=%d?lock=%d?tx1=%d?tx2=%d?last=%d\n",??
  • ????????dev->name,?dev->interrupt,?ei_local->irqlock,?ei_local->tx1,??
  • ????????ei_local->tx2,?ei_local->lasttx);??
  • ????restore_flags(flags);??
  • ????return?1;??
  • ????}??
  • ??
  • ????/*?Mask?interrupts?from?the?ethercard.?*/??
  • ????outb(0x00,?e8390_base?+?EN0_IMR);??
  • ????ei_local->irqlock?=?1;??
  • ????restore_flags(flags);??
  • ??
  • ????send_length?=?ETH_ZLEN?<?length???length?:?ETH_ZLEN;??
  • ??
  • ????if?(ei_local->pingpong)?{??
  • ????????int?output_page;??
  • ????????if?(ei_local->tx1?==?0)?{??
  • ????????????output_page?=?ei_local->tx_start_page;??
  • ????????????ei_local->tx1?=?send_length;??
  • ????????????if?(ei_debug??&&??ei_local->tx2?>?0)??
  • ????????????????printk("%s:?idle?transmitter?tx2=%d,?lasttx=%d,?txing=%d.\n",??
  • ???????????????????????dev->name,?ei_local->tx2,?ei_local->lasttx,??
  • ???????????????????????ei_local->txing);??
  • ????????}?else?if?(ei_local->tx2?==?0)?{??
  • ????????????output_page?=?ei_local->tx_start_page?+?6;??
  • ????????????ei_local->tx2?=?send_length;??
  • ????????????if?(ei_debug??&&??ei_local->tx1?>?0)??
  • ????????????????printk("%s:?idle?transmitter,?tx1=%d,?lasttx=%d,?txing=%d.\n",??
  • ???????????????????????dev->name,?ei_local->tx1,?ei_local->lasttx,??
  • ???????????????????????ei_local->txing);??
  • ????????}?else?{????/*?We?should?never?get?here.?*/??
  • ????????????if?(ei_debug)??
  • ????????????????printk("%s:?No?Tx?buffers?free.?irq=%d?tx1=%d?tx2=%d?last=%d\n",??
  • ????????????????????dev->name,?dev->interrupt,?ei_local->tx1,???
  • ????????????????????ei_local->tx2,?ei_local->lasttx);??
  • ????????????ei_local->irqlock?=?0;??
  • ????????????dev->tbusy?=?1;??
  • ????????????outb_p(ENISR_ALL,?e8390_base?+?EN0_IMR);??
  • ????????????return?1;??
  • ????????}??
  • ????????ei_block_output(dev,?length,?skb->data,?output_page);??
  • ????????if?(!?ei_local->txing)?{??
  • ????????????ei_local->txing?=?1;??
  • ????????????NS8390_trigger_send(dev,?send_length,?output_page);??
  • ????????????dev->trans_start?=?jiffies;??
  • ????????????if?(output_page?==?ei_local->tx_start_page)??
  • ????????????????ei_local->tx1?=?-1,?ei_local->lasttx?=?-1;??
  • ????????????else??
  • ????????????????ei_local->tx2?=?-1,?ei_local->lasttx?=?-2;??
  • ????????}?else??
  • ????????????ei_local->txqueue++;??
  • ??
  • ????????dev->tbusy?=?(ei_local->tx1??&&??ei_local->tx2);??
  • ????}?else?{??/*?No?pingpong,?just?a?single?Tx?buffer.?*/??
  • ????????ei_block_output(dev,?length,?skb->data,?ei_local->tx_start_page);??
  • ????????ei_local->txing?=?1;??
  • ????????NS8390_trigger_send(dev,?send_length,?ei_local->tx_start_page);??
  • ????????dev->trans_start?=?jiffies;??
  • ????????dev->tbusy?=?1;??
  • ????}??
  • ??????
  • ????/*?Turn?8390?interrupts?back?on.?*/??
  • ????ei_local->irqlock?=?0;??
  • ????outb_p(ENISR_ALL,?e8390_base?+?EN0_IMR);??
  • ??
  • ????dev_kfree_skb?(skb,?FREE_WRITE);??
  • ??????
  • ????return?0;??
  • }??

  • ei_receive()函數

    [cpp]?view plaincopy
  • static?void?ei_receive(struct?device?*dev)??
  • {??
  • ????int?e8390_base?=?dev->base_addr;??
  • ????struct?ei_device?*ei_local?=?(struct?ei_device?*)?dev->priv;??
  • ????int?rxing_page,?this_frame,?next_frame,?current_offset;??
  • ????int?rx_pkt_count?=?0;??
  • ????struct?e8390_pkt_hdr?rx_frame;??
  • ????int?num_rx_pages?=?ei_local->stop_page-ei_local->rx_start_page;??
  • ??????
  • ????while?(++rx_pkt_count?<?10)?{??
  • ????????int?pkt_len;??
  • ??????????
  • ????????/*?Get?the?rx?page?(incoming?packet?pointer).?*/??
  • ????????outb_p(E8390_NODMA+E8390_PAGE1,?e8390_base?+?E8390_CMD);??
  • ????????rxing_page?=?inb_p(e8390_base?+?EN1_CURPAG);??
  • ????????outb_p(E8390_NODMA+E8390_PAGE0,?e8390_base?+?E8390_CMD);??
  • ??????????
  • ????????/*?Remove?one?frame?from?the?ring.??Boundary?is?always?a?page?behind.?*/??
  • ????????this_frame?=?inb_p(e8390_base?+?EN0_BOUNDARY)?+?1;??
  • ????????if?(this_frame?>=?ei_local->stop_page)??
  • ????????????this_frame?=?ei_local->rx_start_page;??
  • ??????????
  • ????????/*?Someday?we'll?omit?the?previous,?iff?we?never?get?this?message.?
  • ???????????(There?is?at?least?one?clone?claimed?to?have?a?problem.)??*/??
  • ????????if?(ei_debug?>?0??&&??this_frame?!=?ei_local->current_page)??
  • ????????????printk("%s:?mismatched?read?page?pointers?%2x?vs?%2x.\n",??
  • ???????????????????dev->name,?this_frame,?ei_local->current_page);??
  • ??????????
  • ????????if?(this_frame?==?rxing_page)???/*?Read?all?the?frames??*/??
  • ????????????break;??????????????/*?Done?for?now?*/??
  • ??????????
  • ????????current_offset?=?this_frame?<<?8;??
  • ????????ei_block_input(dev,?sizeof(rx_frame),?(char?*)&rx_frame,??
  • ???????????????????????current_offset);??
  • ??????????
  • ????????pkt_len?=?rx_frame.count?-?sizeof(rx_frame);??
  • ??????????
  • ????????next_frame?=?this_frame?+?1?+?((pkt_len+4)>>8);??
  • ??????????
  • ????????/*?Check?for?bogosity?warned?by?3c503?book:?the?status?byte?is?never?
  • ???????????written.??This?happened?a?lot?during?testing!?This?code?should?be?
  • ???????????cleaned?up?someday.?*/??
  • ????????if?(rx_frame.next?!=?next_frame??
  • ????????????&&?rx_frame.next?!=?next_frame?+?1??
  • ????????????&&?rx_frame.next?!=?next_frame?-?num_rx_pages??
  • ????????????&&?rx_frame.next?!=?next_frame?+?1?-?num_rx_pages)?{??
  • ????????????ei_local->current_page?=?rxing_page;??
  • ????????????outb(ei_local->current_page-1,?e8390_base+EN0_BOUNDARY);??
  • ????????????ei_local->stat.rx_errors++;??
  • ????????????continue;??
  • ????????}??
  • ??
  • ????????if?(pkt_len?<?60??||??pkt_len?>?1518)?{??
  • ????????????if?(ei_debug)??
  • ????????????????printk("%s:?bogus?packet?size:?%d,?status=%#2x?nxpg=%#2x.\n",??
  • ???????????????????????dev->name,?rx_frame.count,?rx_frame.status,??
  • ???????????????????????rx_frame.next);??
  • ????????????ei_local->stat.rx_errors++;??
  • ????????}?else?if?((rx_frame.status?&?0x0F)?==?ENRSR_RXOK)?{??
  • ????????????struct?sk_buff?*skb;??
  • ??????????????
  • ????????????skb?=?alloc_skb(pkt_len,?GFP_ATOMIC);??
  • ????????????if?(skb?==?NULL)?{??
  • ????????????????if?(ei_debug?>?1)??
  • ????????????????????printk("%s:?Couldn't?allocate?a?sk_buff?of?size?%d.\n",??
  • ???????????????????????????dev->name,?pkt_len);??
  • ????????????????ei_local->stat.rx_dropped++;??
  • ????????????????break;??
  • ????????????}?else?{??
  • ????????????????skb->len?=?pkt_len;??
  • ????????????????skb->dev?=?dev;??
  • ??????????????????
  • ????????????????ei_block_input(dev,?pkt_len,?(char?*)?skb->data,??
  • ???????????????????????????????current_offset?+?sizeof(rx_frame));??
  • ????????????????netif_rx(skb);??
  • ????????????????ei_local->stat.rx_packets++;??
  • ????????????}??
  • ????????}?else?{??
  • ????????????int?errs?=?rx_frame.status;??
  • ????????????if?(ei_debug)??
  • ????????????????printk("%s:?bogus?packet:?status=%#2x?nxpg=%#2x?size=%d\n",??
  • ???????????????????????dev->name,?rx_frame.status,?rx_frame.next,??
  • ???????????????????????rx_frame.count);??
  • ????????????if?(errs?&?ENRSR_FO)??
  • ????????????????ei_local->stat.rx_fifo_errors++;??
  • ????????}??
  • ????????next_frame?=?rx_frame.next;??
  • ??????????
  • ????????/*?This?_should_?never?happen:?it's?here?for?avoiding?bad?clones.?*/??
  • ????????if?(next_frame?>=?ei_local->stop_page)?{??
  • ????????????printk("%s:?next?frame?inconsistency,?%#2x\n",?dev->name,??
  • ???????????????????next_frame);??
  • ????????????next_frame?=?ei_local->rx_start_page;??
  • ????????}??
  • ????????ei_local->current_page?=?next_frame;??
  • ????????outb_p(next_frame-1,?e8390_base+EN0_BOUNDARY);??
  • ????}??
  • ????/*?If?any?worth-while?packets?have?been?received,?dev_rint()?
  • ???????has?done?a?mark_bh(NET_BH)?for?us?and?will?work?on?them?
  • ???????when?we?get?to?the?bottom-half?routine.?*/??
  • ??
  • ????/*?Record?the?maximum?Rx?packet?queue.?*/??
  • ????if?(rx_pkt_count?>?high_water_mark)??
  • ????????high_water_mark?=?rx_pkt_count;??
  • ??
  • ????/*?Bug?alert!??Reset?ENISR_OVER?to?avoid?spurious?overruns!?*/??
  • ????outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER,?e8390_base+EN0_ISR);??
  • ????return;??
  • } ?
  • 轉載于:https://www.cnblogs.com/wangfengju/archive/2013/04/13/6173204.html

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。