⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 (ldd) ch14-网络驱动程序(上)(转载).htm

📁 LINUX驱动编程
💻 HTM
📖 第 1 页 / 共 4 页
字号:
            <DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
          <TD width="8%" height=4>
            <DIV align=center><A href="mailto:joyfire@sina.com"><FONT 
            color=#ffffff>联系</FONT></A></DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE borderColor=#666666 cellPadding=2 width="90%" align=center border=2>
  <TBODY>
  <TR>
    <TD bgColor=#000000>
      <P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT 
      color=#ffffff size=2>目录页</FONT></A> | <A 
      href="http://joyfire.net/lsdp/16.htm"><FONT color=#ffffff 
      size=2>上一页</FONT></A> | <A href="http://joyfire.net/lsdp/18.htm"><FONT 
      color=#ffffff size=2>下一页</FONT></A></P>
      <P align=center><FONT face=黑体 color=#ffffff size=6>(LDD) 
      Ch14-网络驱动程序(上)(转载) </FONT></P><SPAN 
      style="LINE-HEIGHT: 1; LETTER-SPACING: 0pt"><FONT color=#ffffff size=3>
      <P>发信人:&nbsp;Altmayer&nbsp;(alt),&nbsp;信区:&nbsp;GNULinux<BR>标&nbsp;&nbsp;题:&nbsp;(LDD)&nbsp;Ch14-网络驱动程序(上)(转载)<BR>发信站:&nbsp;饮水思源&nbsp;(2001年12月13日08:57:57&nbsp;星期四),&nbsp;站内信件<BR>&nbsp;<BR>【&nbsp;以下文字转载自&nbsp;<FONT 
      color=#00ff00>UNIXpost&nbsp;</FONT>讨论区&nbsp;】<BR>【&nbsp;原文由<FONT 
      color=#00ff00>&nbsp;altmayer.bbs@bbs.nju.edu.cn,</FONT>&nbsp;所发表&nbsp;】<BR>&nbsp;<BR>【&nbsp;以下文字转载自&nbsp;<FONT 
      color=#00ff00>altmayer&nbsp;</FONT>的信箱&nbsp;】<BR>&nbsp;<BR>第十四章&nbsp;&nbsp;&nbsp;&nbsp;网络驱动程序<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>我们已经讨论了字符设备和块设备驱动程序,接着要讨论的是迷人的网络世界。网络接<BR>口是Linux设备中的第三标准类,这一章就是讲述它们是如何与核心的其余部分交互的。<BR>&nbsp;<BR>网络接口并不象字符和块设备那样存在于文件系统。相反,它在核心层处理包的发送和<BR>接收,并不与进程中的某个打开的文件绑定在一起。<BR>&nbsp;<BR>网络接口在文件系统中的角色就象被安装的块设备。一个块设备在blk_dev数组和其它核<BR>心结构中注册它的特征,接着按照要求通过它的request_fn函数“发送”和“接收”块<BR>。类似地,一个网络接口必须在特定的数据结构中注册自己,从而在与外部世界交换包<BR>时可以被调用。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>时可以被调用。<BR>&nbsp;<BR>安装的磁盘与包发送接口有几个重要的不同。首先,磁盘以一个结点的形式存在于/dev<BR>目录,而网络接口并不在文件系统中出现。不过两者之间最大的不同在于:磁盘是被请<BR>求向核心发送一个缓冲区,而网络接口则是请求向核心推送进来的包。<BR>&nbsp;<BR>Linux的网络子系统被设计成完全协议无关的。这对网络协议(IP&nbsp;vs.&nbsp;IPX&nbsp;或其它协议<BR>)和硬件协议(以太网vs.令牌环等)都是如此。网络驱动程序和核心之间的交互一次处<BR>理一个网络包;这允许协议可以干净地对驱动程序隐`藏起来,而物理传输则可以对协议<BR>隐藏起来。<BR>&nbsp;<BR>本章描述网络接口如何与核心的其它部分紧密合作,并给出一个基于内存的模块化的网<BR>络接口,称之为(你可能已经猜到了)snull。为简化讨论,这个接口使用以太网硬件协<BR>议并传送IP包。通过snull获得的知识可以很好地应用于IP以外的协议,从以太网移到其<BR>它硬件协议只要求你对使用的物理协议有所了解。<BR>&nbsp;<BR>snull的另一个限制是它不能在Linux1.2中编译。再说一遍,这样做只是为了保持代码简<BR>单,并避免在snull中加入一些另人厌倦的条件。不过,本章将会提到与网络驱动程序相<BR>关的可移植性问题。<BR>&nbsp;<BR>本章并不介绍IP的编号原则,网络协议,以及其它普通的网络概念。这个主题与驱动程<BR>序作者无关,而且以不到几百页的篇幅想对网络技术有一个令人满意的概述是不可能的<BR>。感兴趣的读者可以参考一些讲述网络问题的书。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>。感兴趣的读者可以参考一些讲述网络问题的书。<BR>&nbsp;<BR>在讨论网络设备之前,我想提醒你网络事务中的原子数据项被称做一个八元组(octet)<BR>,由八个数据位组成。在本章中我都这样使用。网络文档从不使用术语“字节”。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>Snull如何设计<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>本节讨论与snull网络接口有关的一些设计概念。尽管这些信息可能显得用处并不大,但<BR>如果不理解它则可能在研究示例代码时遇到一些困难。<BR>&nbsp;<BR>第一位的设计决定(也是最重要的)是示例接口不应绑定于任何实际硬件。实际接口不<BR>依赖于所传送的协议,snull的这个限制并不影响本章给出的示例代码,因为它是协议无<BR>关的。IP限制的唯一影响是地址分配----我们将位示例接口分配IP地址。<BR>&nbsp;<BR>分配IP号码<BR>&nbsp;<BR>snull模块生成两个接口。这样的接口与简单的环回(loopback)并不一样,这里你从一<BR>个接口传送的包总是环回到另一个接口,而不是它自己。它看起来好象是你有两个外部<BR>链接,但实际上你的计算机只是应答自己。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>链接,但实际上你的计算机只是应答自己。<BR>&nbsp;<BR>不幸的是,这个效果并不能仅仅通过IP号码分配来达到,因为核心不会从接口A发送一个<BR>指向它自己接口B的包。相反,这时它会使用环回通道,从而根本不通过snull。为了能<BR>建立一个通过snull接口的通信,源和目的地址必须在数据传送的时候修改一下。换句话<BR>说,从一个接口发出的包应能被另一个接口接收,但外出包的接收者不能被认为是本机<BR>。这也适用于收到包的源地址。<BR>&nbsp;<BR>为了收到这种“隐藏环回”的效果,snull接口反转一下源和目的地址的第三个八元组的<BR>最低位。其效果就是发向网络A(连在接口sn0上)的包在sn1接口上好象是属于网络B。<BR>&nbsp;<BR>为了避免和太多的号码打交道,我们给用到的IP号码分配一些符号名:<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snullnet0是一个连接在sn0接口上的一个C类网络。类似地,snullnet1是连<BR>在sn1上的网络。这两个网络的地址仅在第三个八元组的最低位不同。<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local0是分配给接口sn0的IP地址;它属于snullnet0。与sn1相关联的地址是<BR>local1。local0和local1的第三和第四个八元组必须都不相同。<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remote0是snullnet0中的一个主机,它的第四个八元组与local1相同。所有<BR>发向remote0的包在其C类地址被接口代码修改后将到达local1。主机remote1属于snulln<BR>et1,并且它的第四个八元组与local0相同。<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>snull接口的操作见图14-1,图中与接口相关联的主机名印在接口名旁边。<BR>&nbsp;<BR>下面是几个可能的网络号码。一旦你把这几行写到/etc/networks,你就可以用名字来称<BR>呼这些网络。这些值是从保留私用的号码范围中选取的。<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snullnet0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;192.168.0.0<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snullnet1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;192.168.1.0<BR>&nbsp;<BR>下面是写入/etc/hosts的可能的主机号码:<BR>&nbsp;<BR>192.168.0.88&nbsp;&nbsp;&nbsp;&nbsp;local0<BR>&nbsp;<BR>192.168.0.99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remote0<BR>&nbsp;<BR>192.168.1.99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local1<BR>&nbsp;<BR>192.168.1.88&nbsp;&nbsp;&nbsp;&nbsp;remote1<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>(图14-1&nbsp;Page304)<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>(图14-1&nbsp;Page304)<BR>&nbsp;<BR>不过如果你的计算机已经连到了一个网络上,那么一定要注意。你选择的号码有可能是<BR>实际的Internet或intranet的号码,把它们分配给你的接口可能会妨碍与真正主机的通<BR>信。而且,尽管我给出的这些号码不是实际的Internet号,但也有可能被你的私用网所<BR>适用,如果它处于防火墙之后的话。<BR>&nbsp;<BR>不论你选择什么号码,你可以通过发出下面的命令来正确地设置接口:<BR>&nbsp;<BR>(代码304&nbsp;#1)<BR>&nbsp;<BR>到此为止,接口的“远”端已经可以到达了。下面的屏幕快照显示了我的主机是如何通<BR>过snull到达remote0和remote1的。<BR>&nbsp;<BR>(代码304&nbsp;#2)<BR>&nbsp;<BR>注意你不可能达到属于这两个网络的其它主机,因为在包的地址被改变并被接收到后,<BR>你的计算机会把它丢弃。<BR>&nbsp;<BR>包的物理传送<BR>&nbsp;<BR>至于数据传送,snull属于以太网一类。示例代码使用了核心的以太网支持。这使我们不<BR>必去实现网络设备一些令人厌倦的细节。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>必去实现网络设备一些令人厌倦的细节。<BR>&nbsp;<BR>我选择以太网是因为现存网络的主体----至少与工作站相连的这一部分-----都是基于以<BR>太网技术,不论是10base2,10baseT,还是100baseT。另外,核心还提供了对以太网设<BR>备的一般化的支持,因此没有理由拒绝使用。以太网设备的优势如此明显,连plip接口<BR>(一类使用打印机端口的接口)都自称是以太网设备。<BR>&nbsp;<BR>在snull中使用以太网设置的最后一个优势是你可以在接口上运行tcpdump。不过,如果<BR>你想这样做,你需要把接口称做ethx,而不是snx。snull模块已经准备好将自己声明为e<BR>thx。如果在insmode命令行中指定eth=1,你就选择了这种行为。如果你忘了为snull请<BR>求eth命名,tcpdump会拒绝倾倒这个接口,而是返回一个“未知的物理层类型”错。<BR>&nbsp;<BR>snull接口的另一个设计决定是只处理IP协议,本章的讨论也仅限于IP。不过要注意,接<BR>口驱动程序本身并不依赖于它所处理的底层协议;网络驱动程序根本不查看它所传送的<BR>包。关于多协议传送将在后面的“非以太网包头”中详细介绍。<BR>&nbsp;<BR>不过说实话,snull还是查看包内容的,甚至还要修改它们,因为这是为保证代码工作要<BR>求的。代码修改每个IP包头的源,目的,以及校验和,但不检查它是否真地携带了IP信<BR>息。这种快而脏的数据修改会破坏非IP包。如果你想让snull处理其它协议,你必须修改<BR>这个模块的源码。不过,这种需求不太可能增长,因为每个拥有Linux盒的人都运行IP,<BR>而其它协议则是可选的。<BR>&nbsp;<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>&nbsp;<BR>与核心相连<BR>&nbsp;<BR>我们将通过拆解snull源码来看看网络驱动程序的结构。保证有几个驱动程序的源码在手<BR>边会很有助于你理解我们的讨论。我个人推荐loopback.c,plip.c,以及3c509.c,以逐<BR>渐增加的复杂性排序。有skeleton.c在手边也很有帮助,尽管这个示例驱动程序并不能<BR>真正运行。所有这些文件都居于核心源码树的drivers/net下。<BR>&nbsp;<BR>模块加载<BR>&nbsp;<BR>当一个模块被加载到运行的核心时,它要请求一些资源,并提供一些方便的功能;这已<BR>不再新鲜。另外请求资源的方式也不新鲜。驱动程序要探测它的设备及硬件位置(I/O端<BR>口和IRQ线)----但并不注册它们----就象在第九章中断处理中“安装一个中断处理程序<BR>”一节中介绍的一样。网络驱动程序通过它的函数init_module进行注册的方法与字符或<BR>块设备驱动程序不一样。与请求一个主设备号不同,驱动程序为每个新检测到的接口在<BR>一个网络设备的全局列表中插入一个数据结构。<BR>&nbsp;<BR>每个接口用一个device结构描述。sn0和sn1这两个snull接口的结构如下所示:<BR>&nbsp;<BR>(代码&nbsp;306)<BR>&nbsp;<BR>注意第一个域,既名字域指向一个静态缓冲区,它在加载时将被填充。通过这个方法,<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>注意第一个域,既名字域指向一个静态缓冲区,它在加载时将被填充。通过这个方法,<BR>可以晚点儿选择接口名,下面会给出解释。如果你想在这个结构中使用一个显式缓冲区<BR>,如“01234567”,我要警告你那样可能导致代码不能可靠地工作。这是因为编译器会<BR>将两个重复的串折叠;因此你得到的会是一个缓冲区和两个指向它的缓冲区。而且,编<BR>译器有可能将常量串存在只读内存中,这显然不是你想要的。<BR>&nbsp;<BR>在下节之前我不想完整描述结构device,因为它是一个庞大的结构,太早地肢解它没有<BR>什么好处。我想在驱动程序中使用这个结构,并在每个域被使用时再解释它。<BR>&nbsp;<BR>前面的代码显式地使用了device结构中的name和init域。name是第一个域,含有接口名<BR>(识别接口的字符串)。驱动程序可以将接口名硬写在程序中,也允许动态赋值,其工<BR>作方式如下:如果名字的第一个字符是个空或者空格,那么设备注册项就使用第一个可<BR>用的ethn名。这样第一个以太网接口就被称做eth0,其它的按序号类推。snull接口则被<BR>缺省地称为sn0和sn1。不过,如果在加载时指定eth=1,那么init_module将使用动态赋<BR>值。缺省名由init_module给出:<BR>&nbsp;<BR>(代码307&nbsp;#1)<BR>&nbsp;<BR>init域是个函数指针。任何时候当你注册一个设备时,核心要求驱动程序初始化自己。<BR>初始化就是指探测物理接口,用正确的数值填充device结构,下一节将给予描述。如果<BR>初始化失败,这个结构就不能被链入网络设备的全局列表。这种特别的设置的方法在系<BR>统引导时特别有效;每个驱动程序都试图注册它自己的设备,但只有确实存在的设备才<BR>被链入列表。这与字符和块设备驱动程序不同,它们被组织成一个两级树,由主设备号<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>被链入列表。这与字符和块设备驱动程序不同,它们被组织成一个两级树,由主设备号<BR>和次设备号索引。<BR>&nbsp;<BR>由于真正的初始化在别的地方完成,init_module要做的工作非常少,只需一句如下:<BR>&nbsp;<BR>(代码307&nbsp;#2)<BR>&nbsp;<BR>初始化每个设备<BR>&nbsp;<BR>设备的探测在接口的init函数里完成,它通常被称做“探测”函数。init收到的唯一的<BR>参数是一个指向正被初始化的设备的指针,其返回值是0或者一个负的错误代码----通常<BR>是-ENODEV。<BR>&nbsp;<BR>对snull接口并没有进行实际的探测,因为它未绑定到任何硬件上。当你为一个实际的接<BR>口写实际的驱动程序时,探测字符设备的原则仍然适用:在使用I/O端口之前先检测它们<BR>,在检测期间不要向它写。另外,你还要避免在此时注册I/O端口和中断线。真正的注册<BR>应该推迟到设备打开时;这个非常重要,特别是当中断线被其它设备共享时。每次当别<BR>的设备触发中断线时,你的接口当然不希望被调用,而应简单地回答:不,它不是我的<BR>。<BR>&nbsp;<BR>实际上,在加载时进行设备探测对ISA设备并不鼓励,因为这有可能很危险----ISA体系<BR>结构在容错方面名声不佳。由于这个原因,大多数网络驱动程序在以模块的方式加载时<BR>拒绝为其硬件探测,核心也只探测第一个网络接口,在一个网络设备检测出来后不再进<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>拒绝为其硬件探测,核心也只探测第一个网络接口,在一个网络设备检测出来后不再进<BR>行任何硬件测试。通常dev-&gt;base_addr----当前设备的I/O基地址----决定了要做什么:<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果dev-&gt;base_addr是一个有效的设备I/O地址,将不再探测其它I/O位置,<BR>而是使用这个值。如果这个值在加载时被赋值,这种情况就会发生。<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果dev-&gt;base_addr是0,那么探测设备是可以接受的。拥护可以通过在加载<BR>时置这个I/O地址为0来请求探测。<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其它情况下,不进行探测。核心使用0xffe0来阻止探测,但其实任何无效值<BR>都行。这需要依赖于驱动程序来无声地拒绝base_addr中的一个无效地址。一个模块应该<BR>缺省地置这个地址为无效值来防止不期望的探测。注意查看PCI设备总是安全的,因为它<BR>并不牵扯任何探测(见第15章,外围总线概述)<BR>&nbsp;<BR>正如你可能已经注意到的,用一个加载时的设置来控制探测与我们在skull中使用的技术<BR>是一样的。<BR>&nbsp;<BR>当从dev-&gt;init中退出时,dev结构应该用正确的值填充。初始化例程的主要工作就是填<BR>充这个结构。幸运的是,核心通过函数ether_setup填充结构device负责了一些以太网的<BR>缺省设置。<BR>&nbsp;<BR>snull_init的核心是:<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>(代码308)<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;keep&nbsp;the&nbsp;default&nbsp;flags,&nbsp;just&nbsp;add&nbsp;NOARP&nbsp;*/<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dev-&gt;flags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|=IFF_NOARP;<BR>&nbsp;<BR>这段代码唯一不寻常的特征是在标志中设置IFF_NOARP。这指明接口不能使用ARP,即“<BR>地址解析协议”。ARP是一个低级的以太网协议;每个真实的以太网接口都懂得ARP,因<BR>此不需要设置这个标志。有趣的是注意到一个接口在没有ARP时仍能工作。例如,plip接<BR>口就是没有ARP支持的以太网类接口,与snull相似。这个主题将在后面的“地址解析”<BR>中详细讨论,device结构将在下一节肢解。<BR>&nbsp;<BR>现在我想介绍结构device的另一个域priv。它的作用类似与我们在字符设备驱动程序中<BR>用过的private_data指针。与fops-&gt;private_data不同的是,priv指针是在初始化时分<BR>配,而不是在打开时,因为priv所指向的数据项包含有接口的统计信息。有一点很重要<BR>,就是统计信息要保证总是可用的,即使在接口宕掉时,因为用户可能在任何时候通过<BR>调用ifconfig来显式统计信息。在初始化时而不是打开时分配priv浪费的内存是无关紧<BR>要的,因为多数被探测到的接口保持一直在系统中运行。snull模块为priv声明了一个数<BR>据结构snull_priv。这个结构包含了结构enet_statistics,它是存放接口信息的标准地<BR>方。<BR>&nbsp;<BR>下面这几条snull_init中的语句分配dev-&gt;priv:<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>下面这几条snull_init中的语句分配dev-&gt;priv:<BR>&nbsp;<BR>(代码309&nbsp;#1)<BR>&nbsp;<BR>模块卸载<BR>&nbsp;<BR>当模块被卸载时没有什么特殊的事情发生。函数cleanup_module在释放了与私有结构相<BR>关的内存后,只需将接口从列表中取消即可。<BR>&nbsp;<BR>(代码309&nbsp;#2)<BR>&nbsp;<BR>模块化的和非模块化的驱动程序<BR>&nbsp;<BR>尽管在对字符设备和块设备来说,模块化和非模块化的驱动程序并没有什么引人注意的<BR>区别,但对网络驱动程序来说,情况并非如此。<BR>&nbsp;<BR>如果一个驱动程序做为主流Linux核心的一部分发行的话,它并不声明自己的device结构<BR>,而是使用在drivers/net/Space.c中声明的结构。Space.c声明了所有网络设备的链表<BR>,即包括plip1一类驱动程序特定的结构,也包括通用目的的eth设备。以太网根本不关<BR>心它们的device结构,因为它们使用通用目的的结构。这种通用的eth设备结构声明ethi<BR>f_probe为它们的init函数。程序员要想在主流核心中插入一个新的以太网接口只需要在<BR>ethif_probe中加入一个对驱动程序初始化函数的调用。另一方面,非eth驱动程序的作<BR>者需要在Space.c中插入它们的device结构。在两种情况下,如果驱动程序必须被链到核<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>者需要在Space.c中插入它们的device结构。在两种情况下,如果驱动程序必须被链到核<BR>心,只需要修改源文件Space.c。<BR>&nbsp;<BR>在系统引导时,网络初始化代码循环遍历所有的device结构,调用它们的探测函数(dev<BR>-&gt;init),向它们传递一个指向设备本身的指针。如果探测函数成功了,Space.c初始化<BR>device结构。这种设置驱动程序的方式允许渐增地将设备赋予名字eth0,eth1,依次类<BR>推,而不需要改变每个设备的name域。<BR>&nbsp;<BR>另一方面,当加载一个模块化的驱动程序时,它声明它自己的device结构(入我们在本<BR>章中已经看到的那样),即使它控制的接口是以太网接口。<BR>&nbsp;<BR>好奇的读者可以查看Space.c和net_init.c来得到更多关于接口初始化的信息。这里对驱<BR>动程序设置的介绍只是为了强调init设备方法的重要性。如果一个驱动程序模块包含了<BR>预填好的设备结构,那么它将不适合主流核心的初始化技术,并且如果结构device中引<BR>入新的域,会使它变的不能向前兼容。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>设备结构的细节<BR>&nbsp;<BR>device结构居于网络驱动程序的真正核心,值得完全的描述。第一次阅读本书的读者可<BR>以跳过本节,因为开始时不需要对这个结构有详细的理解。下面的列表描述所有的域,<BR>但主要目的是提供一个参考而不是要被记住。本章的其余部分在一个域被示例代码用到<BR></P></FONT><FONT 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -