1、摘 要Linux技术是当前计算机技术中最大的一个热点,在我国以及全世界得到了迅猛的发展,被广泛的应用于嵌入式系统、服务器、网络系统、安全等领域。从而使得掌握在Linux环境下的开发技术,成为了计算机行业中引人注目的焦点。以Linux为代表的自由操作系统的优点之一,是它们的内部是开放的。Linux内核保留有大量的复杂代码,通常设备驱动提供了一个门路,使硬件特殊的一部分响应定义好的内部编程接口,它们完全隐藏了设备工作的细节。用户的活动通过一套标准化来进行,设备驱动就是将这些调用映射到作用于实际硬件和设备相关的操作上。论文首先介绍了Linux下设备驱动程序设计的基本知识,其中包括对Linux的发展历
2、程、内核、特性的概述,Linux设备的分类及编写驱动程序的一些基本概念等,以及模块的加载和卸载。其次介绍了ARM驱动程序开发的硬件环境和软件环境。阐述了该驱动程序在开发时的需求分析。第三对Linux环境下网卡驱动程序的设计与实现作了理论上的探讨,重点从网卡驱动模块的加载、网络设备的初始化、设备打开与关闭、数据的发送与接收、信息统计、网卡驱动模块的卸载等方面按步骤的进行了详细的讨论。通过组建在Linux操作系统下的TCP/IP网络,来分配IP地址以及区分网络号和主机号的子网掩码,通过配置DHCP服务器,实现动态地为主机配置IP参数,解决手工配置存在的问题。最后介绍了在驱动程序开发设计过程中所遇到
3、的问题和困难以及是如何去克服这些困难的,并提出了今后的努力方向。关键词:Linux; 模块; 网络; 驱动; 寄存器 I AbstractLinux technology is a hotspot among computer technology nowadays, and it developes at high speed not only in our country but also in the whole world, and it has applied widely in embedded system, server, network system, security ar
4、ea and so on. So it makes that grasping the development technology under the Linux environment is more and more noticeable in computer industry. One of the many advantages of free operating systems, as typified by Linux, is that their internals are open for all to view. The Linux kernel remains larg
5、e and complex body of code. User activities are performed by means of a set of standardized calls that are independent of the specific driver; mapping those calls to device-specific operations that act on real hardware is then the role of the device driver.This thesis firstly introduces the fundamen
6、tal knowledge about design of linux device driver, which generally includes the development procedure, kernel, and characteristic of linux. Meanwhile, the categorization of linux device, elemental terminology of exploiting network interface card driver, and loading and unloading the driver module ar
7、e also mentioned in this thesis. Secondly, this thesis also presents both the hardware and software environment of the driver development, and the requirement specification of driver development are elaborated here. Thirdly, combined with the driver of ARM, this thesis discusses the design and reali
8、zation of the network interface card driver in theory, especially makes more detailed discussions step by step, such as loading the driver module, initialization of the device, starting and stopping of the device, transmission and receiving of data, information statistics, unloading the driver modul
9、e, etc. Allocating IP addresses and subnet masks differentiating network and host, through construction of TCP/IP network in Linux. Configuring hosts IP arguments dynamically to well solve the problem of manual configuration, through configuration of DHCP server. Finally, this thesis lists all the p
10、roblems and difficulties met during the whole process of designing driver, and how to conquer them and advanced direction of future study are also recounted.Keywords: linux; module; network; driver; registerIII 目 录摘 要IAbstractII第1章 绪论11.1 研究背景11.2 国内外研究现状、目的及意义11.3 本文主要工作2第2章 Linux下设备驱动程序设计的基本知识42.1
11、 Linux概述42.1.1 Linux内核简介42.1.2 Linux的特性62.2 Linux设备驱动程序概述72.2.1 Linux设备驱动程序分类82.2.2 编写网络驱动程序的一些基本概念9第3章 Linux网卡驱动程序设计的理论探讨103.1 Linux下网卡驱动程序设计的数据结构和基本方法103.1.1 网卡驱动程序设计要用到的数据结构103.1.2 网卡驱动程序的基本方法133.1.3 套接字缓冲区介绍143.2 驱动模块的加载和卸载17第4章 系统分析194.1 S3C2410 ARM 开发板介绍194.2 需求分析以及MII接口194.3 寄存器的访问方式21第5章 网卡驱
12、动的具体实现225.1 驱动程序的设计225.2 网卡驱动实现245.2.1 模块的加载及设备初始化245.2.2 设备成员及函数的初始化265.2.3 设备注册、打开、关闭305.2.4 数据的接受和发送325.2.5 参数设置及数据统计345.2.6 网卡数据信息统计36第6章 结论37参 考 文 献38致 谢3939沈阳工业大学本科生毕业设计第1章 绪论1.1 研究背景Linux目前是计算机技术的一大热点,最近几年在我国得到迅猛发展,被广泛应用在嵌入式系统、服务器和桌面应用等领域。Linux操作系统是UNIX操作系统的一种克隆版本,是目前世界上用户最多的一种类UNIX操作系统。作为一个开
13、放源代码的操作系统,它为人们深入了解操作系统的工作原理提供了极好的机会。Linux作为一个开放源代码的操作系统,具有稳定、高效、易裁减和硬件持广泛等特点,被广泛应用于嵌入式系统开发领域。在Linux系统下设计驱动程序简洁、操作方便、功能强大,但是支持的函数却较少,只有一些来源于内核Kernel中的函数。因此,在嵌入式Linux系统开发应用时,需要开发自己专用的网络接口卡,这时不仅要在硬件上保证与Linux的兼容性,而且在软件上需要开发全新的驱动程序。文章在分析了Linux 网络设备驱动程序的结构组成和工作原理之后,重点探讨了Linux环境下网卡驱动程序的开发技术,详细讨论了实用的网卡驱动的开发
14、流程及具体实现细节。1.2 国内外研究现状、目的及意义Linux是由芬兰的赫尔辛基大学 (Helsinki)学生Linus Torvalds把Minix 系统向x86移植的结果。当时 Linus 手边有个 Minix 系统(UNIX 的一个分支),他对这个操作系统相当有兴趣,由于当时他正好有一台个人计算机,他想把这个系统移植到该计算机(x86 架构)上来使用。由于受益于Stallman提倡的开放源代码(Open Source)思想,他得以接触到UNIX操作系统的一些源代码,并仔细研读了UNIX 的核心,然后去除较为繁复的核心程序,将它改写成能够适用于一般个人计算机的一种操作系统,即Linux系
15、统的雏形。1992年1月,大概只有100人开始使用Linux,但他们为Linux的发展壮大作出了巨大贡献。他们对一些不合理的代码进行了改进,修补了代码错误并上传补丁。Linux的腾飞最关键的因素是获得了自由软件基金(FSF)的支持,他们制定了一个GNU计划,该计划的目标就是要编写一个完全免费的 UNIX版本 包括内核及所有相关的组件,可以让用户自由共享并且改写软件,而Linux正好符合他们的意愿。他们将Linux与其现有的GNU应用软件很好地结合起来,使Linux拥有了图形用户界面。1994年3月, Linux 1.0正式版发布,它的出现无异于网络的“自由宣言”。从此Linux用户迅速增加,L
16、inux的核心开发小组也日渐强大。在Linux所包含的数千个文件中,有一个名为Credits的文件,里面列出了100多名对Linux有过重要贡献的黑客,包括他们的名字、地址以及所做的工作。目前国内外所使用的Linux系统一般是指由Linux核心、外壳(SHELL)及外围应用软件构成的发行版本。Linux发行版本是不同的公司或组织将Linux核心、外壳、安装工具、应用软件有效捆绑起来的结果,所以种类繁多,各有各的优缺点。但就其总体而言,这些发行版本具有对尽可能多的网卡的支持。就象UNIX,Linux支持的网卡主要是以太网卡。如3COM、ACCTON、ATT、IBM、CRYSTAL、DLINK等众
17、多品牌的以太网卡只要安装配置正确,都可以得到你所期望的效果。Linux核心已经实现了OSI参考模型的网络层及更上层部分。网络层的实现依靠于数据链路层的有效工作。网卡的驱动程序就是数据链路层与物理层的接口。通过调用驱动程序的发送例程向物理端口发送数据,调用驱动程序的接收例程从物理端口接收数据。Linux系统的设备主要分为字符设备(char device),块设备(block device)和网络设备(network device)三种。Linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码长度的日益增加,主要就是驱动程序的增加。Linux 网络设备驱动程序是Linux 操作系统内
18、核的一个重要组成部分,对Linux网络设备驱动程序的原理与设计技术的掌握,有助于理解网络链路层的工作原理,它对从事基于Linux平台的网络产品开发具有十分重要的意义。1.3 本文主要工作首先,论文将重点研究device数据结构,这是了解网卡设备的最好入口点。Linux网络驱动程序的体系结构分为四层,从上到下分别为协议接口层、网络设备接口层、设备驱动功能层、网络设备以及网络媒介层。设计网络驱动程序时,最主要的工作就是完成设备驱动功能层,使其满足自己所需要的功能。在Linux中,把所有的网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合,由struct device数据结构来表示,即
19、网络设备接口,所有的网络设备接口构成一个链表,该链表由dev_base为头指针,链表中的元素代表一个网络设备接口。其次,论文从整体上对驱动程序进行了分块设计,主要由模块加载、网络设备初始化、注册、设备打开与关闭、数据的发送与接收等模块构成。采用这种构成模式易于功能的分割以及程序的调试,在完成初期工作后,方便设备驱动的功能扩展,为后期开发减少工作。最后,每个网络设备都声明了很多能操作它的函数,应该熟悉较多的能够对网络接口进行操作的函数,论文深入的研究了Linux下模块设计的必要性,并通过编写这些操作函数来实现网卡驱动模块的加载以及网络设备的初始化、设备打开与关闭、数据的发送与接收、信息统计、网卡
20、驱动模块的卸载等功能,章节中对重要函数都进行了详细的说明,这些实现了网卡驱动的基本要求。第2章 Linux下设备驱动程序设计的基本知识在进行Linux设备驱动程序的具体讨论之前,有必要对Linux本身以及网卡设备等方面做一个大致的了解和认识。在本章节中,从介绍Linux的诞生开始,由浅入深的进入到Linux内核,最后过渡到对网络设备驱动的介绍。2.1 Linux概述Linux操作系统是UNIX操作系统的一种克隆版本,最早是由芬兰大学的学生Linus Torvalds于1991年开始开发的,并于1991年的10月5日第一次正式向外公布,以后借助于互联网,经过一群遍布于全世界的Internet上的
21、自愿参加的程序员的不懈努力,加上计算机公司的支持,Linux的影响和应用日益广泛,发展成为目前世界上用户最多的一种类UNIX操作系统。Linux 目前是计算机技术的一大热点之一,最近几年在我国得到迅猛发展,被广泛应用在嵌入式系统、安全产品、服务器和桌面应用等领域。经过十多年的发展,到2003年,Linux 2.6内核被发布,这在Linux发展史中具有极其重要的作用。今天,在全世界的Internet上的自愿参加的程序员们和计算机公司的共同努力下,Linux继续飞速的向前发展。2.1.1 Linux内核简介在最开始的时候,Linux系统并没有现在所看到的Linux系统的体积这么庞大,各种免费开放的
22、驱动代码也还没有来得及加入到系统中,所以,之初的Linux实际意义上就是Linux内核。首先来分析一下Linux操作系统的体系结构,可以从两个层次上来考虑操作系统,如下图 2-1所示:图2-1 GNU/Linux操作系统的基本体系结构图最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。GNU C Library (glibc)也在这里,它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间,每个用户空间的进程都使用自己的虚拟地址空间,
23、而内核则占用单独的地址空间。实际上,体系结构可能并不像图1所示的一样清晰。例如,处理系统调用(从用户空间切换到内核空间)的机制可能在各个体系结构上都不相同。Linux系统支持多个进程的并发运行,每个进程都请求系统资源,比如运算、内存、网络连接或其他一些资源等。内核负责处理所有这些请求,根据内核完成任务的不同,可以将内核划分成如下图2-2的功能模块:图2-2 Linux系统模块及功能图2.1.2 Linux的特性Linux是个人计算机和工作站上的Unix类操作系统,但是,它绝不仅仅是简化的Unix系统。相反,Linux是具有创新意义的Unix类操作系统。它不仅继承了Unix的特征,而且在许多方面
24、超过了Unix。作为Unix类操作系统,Linux内核具有下列基本特征:Linux内核的组织形式为整体式结构。整个Linux内核由很多过程组成,每个过程可以独立编译,然后用连接程序将其连接在一起成为一个完整的目标程序。从信息隐藏的观点看,它没有任何程度的隐藏,每个过程都对其它过程都是可见的。这种结构的最大特点是内部结构简单,子系统间易于访问,因此内核的工作效率较高。另外,基于过程的结构也有助于不同的人参与不同过程的开发,从这个角度来说,Linux内核又是开放式的结构,它允许任何人对其进行修正、改进和完善。Linux的进程调度方式简单而有效。可以说Linux在追求效率和调度方式上也是优势明显。对
25、于用户进程,Linux采用简单的动态优先级调度方式;对于内核中的例程(如设备驱动程序、中断服务程序等)则采用了一种独特的机制软中断机制,这种机制保证了内核例程的高效运行。Linux支持内核线程(或称守护进程)。内核线程是在后台运行而又与终端或登录shell结合在一起的进程。Linux中有许多标准的内核线程,其中有一些周期地运行来完成特定的任务(如swapd),而其余一些则连续地运行,等待处理某些特定的事件(如inetd和lpd)。内核线程可以说是用户进程,但和一般的用户进程又有不同,它象内核一样不被换出,因此运行效率较高。Linux支持多种平台的虚拟内存管理。内存管理是和硬件平台密切相关的部分
26、,为了支持不同的硬件平台而又保证虚拟存储管理技术的通用性,Linux的虚拟内存管理为不同的硬件平台提供了统一的接口,因此把Linux内核移植到一个新的硬件平台并不是一件很困难的事。Linux内核另一个独具特色的部分是虚拟文件系统(VFS)。虚拟文件系统不仅为多种逻辑文件系统(如ext2,fat等)提供了统一的接口,而且为各种硬件设备(作为一种特殊文件)也提供了统一接口。Linux的模块机制使得内核保持独立而又易于扩充。模块机制可以使内核很容易地增加一个新的模块(如一个新的设备驱动程序),而无需重新编译内核;同时,模块机制还可以把一个模块按需添加到内核或从内核中卸下,这使得我们可以按需要定制自己
27、的内核。增加系统调用以满足开发者的特殊需求。一般来说,系统调用是操作系统的设计者提供给用户使用内核功能的接口,但Linux开放的源代码也允许你设计自己的系统调用,然后把它加入到内核。网络部分采用了面向对象的设计思想,使得Linux内核支持多种协议、多种网卡驱动程序变得更加的容易,为驱动的开发提供了便捷性,减少了工作量,提高了工作效率。2.2 Linux设备驱动程序概述驱动程序在 Linux内核里扮演着特殊的角色。它们是截然不同的黑盒子,使某个特定硬件响应一个定义好的内部编程接口,这些接口隐藏了设备工作的细节。用户的活动通过一套标准化的调用来执行,而这些调用独立于特定的驱动程序。设备驱动程序的角
28、色就是将这些调用映射到作用于实际硬件设备相关的操作上。 这个编程接口能够使得驱动程序独立于内核的其他部分而建立,必要的情况下可在系统运行时“插入”到内核。这种模块化的的特点使得Linux驱动程序的编写非常的简单,因此内核驱动程序的数目也增长及其迅速,目前已经有成百上千的驱动程序可以在linux下被使用。2.2.1 Linux设备驱动程序分类Linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。Linux系统的设备分为字符设备(chardevice),块设备(blockdevice)和网络设备(networkdevice)三种:字符设备:字符
29、(char)设备是个能够像字节流一样被访问的设备,由字符设备的驱动程序来实现这种特性。字符终端(/dev/console)和串口(/dev/ttys0以及类似设备)就是两个字符设备,他们能够良好的说明“流”这种抽象概念。字符设备可以通过文件系统节点来访问,比如/dev/tty1和/dev/loop0等。这些设备和普通文件之间的唯一差别在于对普通文件的访问可以前后移动访问位置,而大多数字符设备是一个只能顺序访问的数据通道。当然,也存在具有数据特性的字符设备,访问它们时可以前后移动访问位置。例如,帧抓取器就是这样一个设备,应用程序可以用mmap或lseek访问抓取的整个图象。块设备:如同字符设备,
30、块设备也是通过位于/dev目录下的文件系统节点来存取。块设备上能够容纳文件系统。Linux可以让应用程序像字符设备一样地读写块设备,允许依次传递任意多的字节的数据。在内核中,和字符驱动程序相比,块驱动程序具有完全不同的接口,但这些不同对上层用户来说是完全透明的。网络接口:任何网络事件都是通过一个网络接口形成的,一个网络接口就是一个能够和其他主机交换数据的设备。通常,接口都是硬件设备,但也可能是纯软件设备,比如回环(loopback)接口。网络接口由内核中的网络子系统驱动,负责数据包的接收和发送,但它不需要了每项事务是如何映射到实际传送的数据包的。许多网络连接是面向流的,但网络设备却围绕数据包的
31、传输和接收而设计。网络驱动程序不需要知道各个连接的相关信息,它只要处理数据包即可。由于不是面向流的设备,因此将网络接口映射到文件系统中的节点(比如/dev/tty1)比较困难。Unix访问网络接口的方法仍然是给他们分配一个唯一的名字(比如eth0),但这个名字在文件系统中不存在对应的节点。内核和网络设备驱动程序间的通信,完全不同于内核和字符设备以及块驱动程序之间的通信,内核调用一套和数据传输相关的函数而不是read、write等。2.2.2 编写网络驱动程序的一些基本概念无论是什么操作系统的驱动程序,都有一些通用的概念。操作系统提供给驱动程序的支持也大致相同。下面简单介绍一下网络设备驱动程序的
32、一些基本的也是最重要的概念。发送和接收:这是一个网络设备最基本的功能。一块网卡所做的工作无非就是数据的发送和接收,所以在驱动程序中必须要告诉系统数据的发送函数在哪里,系统在有数据要发送时就会调用发送程序。驱动程序由于是直接操纵硬件的,所以网络硬件有数据收到时,最先能得到这个数据的就是驱动程序,它负责把这些原始数据进行必要的处理,然后送给系统。这里,操作系统必须要提供两个机制,一个是找到驱动程序的发送函数,一个是驱动程序把收到的数据送给系统。中断:中断在现代计算机结构中占有重要的地位。操作系统必须提供驱动程序响应中断的能力。一般是把一个中断处理程序注册到系统中去,操作系统在硬件中断发生后调用驱动
33、程序的处理程序。Linux支持中断的共享,即多个设备共享一个中断。时钟:在实现驱动程序时,很多地方会用到时钟。如某些协议里的超时处理,没有中断机制的硬件的轮询等,操作系统应为驱动程序提供定时机制,一般是在预定的时间过了以后,系统自动回调注册的时钟函数。在网络驱动程序中,如果硬件没有中断功能,定时器可以提供轮询(poll)方式对硬件进行存取,或者是实现某些协议时需要的超时重传等。第3章 Linux网卡驱动程序设计的理论探讨网络接口是第三类标准Linux设备,网络设备使用特定的内核数据结构注册自身,以备与外界进行数据交换时调用。网络驱动程序异步地接收来自外部世界的数据包,并且向内核请求把外部获得的
34、数据包发送给内核。内核中的网络驱动程序接口是为不同模式的操作而精心设计的。3.1 Linux下网卡驱动程序设计的数据结构和基本方法网络驱动程序能够完成数据的接收和传输,依靠的是网络驱动程序的数据结构以及其对该数据结构进行操作的设备方法。3.1.1 网卡驱动程序设计要用到的数据结构net_device1结构处于网络驱动层的非常核心的位置并且值得完全的描述。 它也是我们了解一个网卡设备的最好入口点。(1) 全局信息结构 net_device 的第一部分是由下面成员组成:char nameIFNAMSIZ;设备名称。如果名称由驱动程序设置,会包含一个%d格式串, register_netdev 将用
35、一个数字来替换它,使它成为一个唯一的名子,分配的编号从0开始。unsigned long state;设备状态。这个成员包括若干个标志。驱动程序在正常情况下不直接操作这些标志,相反,内核提供了一组工具函数来专门操作该标志。struct net_device *next;指向全局列表中下一个设备的指针。驱动程序不应该修改这个成员。int (*init)(struct net_device *dev);初始化函数。如果设置了这个指针,这个函数被 register_netdev 调用来完成对net_device结构的初始化。大部分现代的网络驱动程序不再使用这个函数了,相反,它们是在注册接口前完成初始
36、化工作的。(2).硬件信息下面的成员包含了相对简单设备的低层硬件信息。它们是早期 Linux 网络特点的延续,大部分现代驱动程序仍然使用它们。unsigned long rmem_end;unsigned long rmem_start;unsigned long mem_end;unsigned long mem_start;设备的内存信息.。这些成员保存了设备使用的共享内存的开始地址和结束地址。如果设备有不同的接收和发送内存,mem成员由发送内存使用,rmem成员由接收内存使用。rmem成员在驱动之外从不被引用。根据规定,end成员的设置要保证end - start等于可用的板卡内存量。u
37、nsigned long base_addr;网络接口的I/O基地址。这个成员由驱动在设备探测时赋值。 Ifconfig命令可用来显示或修改当前值。base_addr可以在系统启动时、或者在模块加载时在内核命令行中显式赋值。这个成员和内存成员一样,内核不使用它们。unsigned char irq;被赋予的中断号。当接口被列出时,ifconfig命令打印出dev-irq的值。这个值常常在启动或者加载时设置,其后可以通过ifconfig命令修改。unsigned char if_port;指定在多端口设备中使用哪个端口。例如,如果这个设备同时支持同轴电缆(IF_PORT_10BASE2)和双绞线
38、(IF_PORT_100BSAET)以太网连接,就可以使用该变量。完整的已知端口类型设置定义在。unsigned char dma;为设备分配的DMA通道。这个成员只对某些外设总线有意义,例如 ISA。 除了用于显示信息(ifconfig命令)之外,它不在设备驱动自身以外使用。c).接口信息有关接口的大部分信息由ether_setup函数正确设置,或者任何其他对给定硬件类型适合的设置函数。以太网卡可以依赖这个通用的函数设置大部分这些成员,但是flags和dev_addr成员是特定设备的, 必须在初始化期间显示赋值。一些非以太网接口可以使用类似ether_setup的辅助函数。deviers/n
39、et/net_init.c 输出了一些类似的函数,包括下列:void ltalk_setup(struct net_device *dev);设置一个 LocalTalk 设备的函数。void fc_setup(struct net_device *dev);初始化光通道设备。void fddi_setup(struct net_device *dev);配置一个光纤分布数据接口(FDDI)网络的接口。void hippi_setup(struct net_device *dev);初始化高性能并行接口(HIPPI)的高速互连驱动的成员。void tr_setup(struct net_dev
40、ice *dev);处理令牌环网络接口的设置。大部分设备都归于这些类别中的一类。如果设备是一个崭新的类,就需要手工设置下面的成员:unsigned short hard_header_len;硬件头部长度,即数据包中位于IP头、或者其他协议信息之前的octet数目。对于以太网接口hard_header_len的值是14(ETH_HLEN)。unsigned mtu;最大传输单元(MTU)5。网络层使用该成员变量驱动数据包的传输。以太网的MTU是1500octet (ETH_DATA_LEN)。unsigned long tx_queue_len;设备发送队列中可以排队的最大帧数。这个值由eth
41、er_setup设置为100,但是可以改它。例如,plip设置为10来避免浪费系统内存(相比真实以太网接口,plip 有一个低些的吞吐量)。unsigned short type;接口的硬件类型.。这个type成员由ARP用来决定接口支持什么样的硬件地址。对以太网接口正确的值是ARPHRD_ETHER,这是由ether_setup设置的值。可识别的类型定义于中。unsigned char addr_len;unsigned char broadcastMAX_ADDR_LEN;unsigned char dev_addrMAX_ADDR_LEN;硬件(MAC)地址长度和设备硬件地址。以太网地址
42、长度是6个字节(即接口板卡的硬件ID),广播地址由6个0xff字节组成。ether_setup会对上述值进行正确地设置。另外,设备地址必须以特定于设备的方式从接口板卡中读出,驱动程序应当将它拷贝到dev_addr中。unsigned short flags;int features;这个flags 成员是一个位掩码。某些标志由内核管理,而其他一些则由接口在初始化期间设置,用来声明接口的各种能力及其他特性。有效的标志定义在中。3.1.2 网卡驱动程序的基本方法每个网络设备都声明了很多能操作它的函数。在这里讨论一下能够对网络接口进行的操作。有些操作可以留作NULL,其他的一些则无需修改, 因为et
43、her_setup给它们赋予了正确的方法。网络接口的设备方法可分为两个类型:基本的和可选的。基本方法包括使用接口必须的方法;可选的方法实现了更为高级的功能,但并不是严格要求的功能。下面的是基本方法:int (*open)(struct net_device *dev);打开接口。在ifconfig8,9激活接口时,接口将被打开。open方法应该注册设备需要的所有系统资源(I/O口、IRQ、DMA等等),打开硬件,并对设备执行其他所需的设置。int (*stop)(struct net_device *dev);停止接口。当接口终止时当它应该被关闭。在该函数中执行的操作与打开时执行的操作是相反的
44、。int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);该方法初始化数据包的传输。完整的数据包(协议头和所有)包含在一个套接字缓存区(sk_buff)结构中。int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);该方法根据之前取到的源和目的硬件地址来建立硬件头,并在 hard_start_xmit前被调用。该函数的任
45、务是将作为参数传入的信息组织成一个合适的特定于设备的硬件头。eth_header是以太网类型接口的默认函数, ether_setup将该成员赋值成eth_header。int (*rebuild_header)(struct sk_buff *skb);该函数用来在ARP4解析完成之后、在报文发送之前重新建立硬件头。在以太网设备使用的缺省的函数中通过使用ARP协议来填充数据包缺少的硬件地址信息。void (*tx_timeout)(struct net_device *dev);如果数据包的传输在合理的时间段内失败了,则假定中断或接口被锁住,这时,网络代码将调用该方法,它负责解决问题并重新开始
46、数据包的传输。struct net_device_stats *(*get_stats)(struct net_device *dev);任何时候当一个应用程序需要获取接口的统计信息,则调用这个方法。例如,当ifconfig或者netstat -i运行时将利用到该方法。int (*set_config)(struct net_device *dev, struct ifmap *map);在改变接口配置时,这个方法是配置驱动的入口点。设备的 I/O 地址和中断号可以通过运行set_config来改变。在探测不到接口时,系统管理员可使用该函数。除开上面提及到的基本方法以外,还有很多的可选方法。通
47、过这些可选的方法,实现禁止中断、轮询模式操作接口、执行接口特有的ioctl命令、改变硬件地址、改变接口的MTU、以及hh-cache的查询更新等功能。3.1.3 套接字缓冲区介绍套接字缓冲区这个结构处于 Linux 内核网络子系统的核心,Linux内核中网络数据包的传输和接收都是通过套接字缓冲区实现的。在中, 能看到该结构和函数原型。(1). 重要成员变量这里描述的成员都是驱动程序需要访问的。struct net_device *dev;接收或发送该缓冲区的设备。union /* */ h;union /* */ nh;union /*/ mac;指向报文中包含的各级的头的指针。union中的
48、每个成员都是一个不同数据结构类型的指针。h中含有传输层头部指针(例如struct tcphdr *th);nh包含网络层头部(例如struct iphdr *iph);以及mac包含链路层头部指针(例如struct ethkr * ethernet)。网络驱动程序要负责设置传入数据包的mac指针,这个任务正常是由 eth_type_trans 处理,但是非以太网驱动不得直接设置skb-mac.raw。unsigned char *head;unsigned char *data;unsigned char *tail;unsigned char *end;指向数据包中数据的指针。head 指向分配内存