📄 6.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://bbs.fudan.edu.cn"><font face="黑体"><big><big>日月光华</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center"> 基于linux的嵌入式系统研究 </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="基于linux的嵌入式系统研究.htm">回到开始</a>][<a href="基于linux的嵌入式系统研究.htm">上一层</a>][<a href="7.htm">下一篇</a>]
<hr><p align="left"><small>发信人: smilecrying (越龙), 信区: Embedded <br>
标 题: 基于linux的嵌入式系统研究(6) <br>
发信站: 日月光华 (2003年05月25日16:36:45 星期天) <br>
<br>
<br>
第五章 Linux对TCP/IP网络的支持 <br>
在毕业设计期间,为了研究如何能够让嵌入式系统支持象Linux一样强大的网络支持, <br>
意分析了Linux的网络协议栈(TCP/IP)的实现,重点放在Linux的TCP/IP网络协议栈的整 <br>
体结构和Linux网络设备驱动程序上面。下面将主要介绍Linux中的网络部分的概述,并且 <br>
将对Linux中ne2000网络设备驱动程序的分析作为对Linux网络设备支持的例子进行解释。 <br>
在第三节提出如何利用Linux的网络协议栈来应用于嵌入式系统,并且提出设计构思。 <br>
5.1 Linux网络概述 <br>
网络和Linux是密切相关的。从某种意义来说Linux是一个针对Internet和WWW的产品。因为 <br>
它的开发者和用户都是通过Web来交换信息思想、程序代码,并且Linux本身也常常被用来 <br>
支持各种组织机构的网络需求。Linux所支持的TCP/IP协议栈是目前Web上最流行和通用的 <br>
网络协议。TCP/IP协议最初是为支持ARPANET(一个美国政府资助的研究性网络)上计算机 <br>
通讯而设计的。ARPANET提出了一些网络概念如包交换和协议分层(一个协议使用另一个协 <br>
议提供的服务)。1988年的时候,APRANET不再得到利用,但是由它延续下来的 (NSFNET和 <br>
Internet)却变得更大了。现在我们所熟知的万维网World Wide Web就是从ARPANET演变过 <br>
来的,它就是建立在Internet基础之上的。Unix TM被广泛应用于ARPANET,实现了对Inte <br>
rnet的全面支持,它的第一个网络版本是4.3 BSD。 <br>
Linux的网络实现就是以4.3 BSD为模型的,它支持BSD sockets(及一些扩展)和所有的TCP <br>
<br>
<br>
/IP网络。Linux选用这个编程接口是因为它很流行,并且有助于应用程序从Linux平台移植 <br>
到其它Unix 平台。 Linux下的TCP/IP网络协议栈的各层之间是通过一系列互相连接层的 <br>
软件来实现Internet地址族的,结构层次如下图所示: <br>
BSD socket层由专门用来处理BSD Socket的通用套接字管理软件来处理,它由INET soc <br>
<br>
et层来支持。INET Socket为基于IP的协议TCP和UDP管理传输端点。UDP(用户数据报协议 <br>
)是一个无连接协议而TCP(传输控制协议)是一个可靠的端对端协议。传输UDP包的时候 <br>
,Linux不知道也不关心是否它们安全到达了目的地。TCP则不同,在TCP连接的两端都需要 <br>
加上一个编号以保证传输的数据被正确接收。在IP层,实现了Internet协议的代码。这些 <br>
代码要给传输的数据加上一个IP头,并且知道如何把传入的IP包送给TCP或者UDP协议。在 <br>
IP层以下,就是网络设备来支持所有的Linux网络工作,如PLIP、SLIP和以太网。不过要注 <br>
意,这些网络设备不一定都是物理设备,可以使用像Loopback这样的虚拟网络设备,纯粹 <br>
是用软件来实现的。 <br>
<br>
5.2 Linux网络设备驱动程序的分析 <br>
下面介绍在Linux中对ne2000/1000兼容网卡的驱动程序分析,这种实现方法可以利用于我 <br>
们开发在Linux内核下的网卡驱动程序上。关于ne2000的网卡设备驱动程序的分析,主要是 <br>
集中于Linux源代码目录下的drivers/net/ne.c和 drivers/net/8390.c,前者是实现了对 <br>
ne2000网卡的数据传输的操作实现,后者是网卡上的底层操作函数实现。 <br>
5.2.1 Linux中网络驱动程序介绍 <br>
在Linux中,为了简化对设备的管理,将所有的外围设备都归结为三类:字符设备(如 <br>
<br>
<br>
盘,鼠标等)、块设备(如硬盘、软驱等)和网络设备(如网卡、串口等等)。为了将网 <br>
络环境中的物理网络设备的多样性屏蔽,Linux对所有的网络物理设备抽象并且定义了一个 <br>
统一的概念:接口(Interface)。对于所有的网络硬件的访问都是通过接口进行访问的, <br>
接口实际上提供了一个对于所有类型的网络硬件的一致化的操作集合,用来处理对数据的 <br>
发送和接收。对于每一个已经驱动了的网络设备,都用一个struct device的数据结构表示 <br>
。在内核启动或者驱动模块插入时,通过网络驱动程序,向系统注册检测到的网络设备。 <br>
在进行网络数据传输的时候,网络驱动程序需要负责通过标准的接口将数据发送到相应的 <br>
网络层,或者向网络发送数据包。 <br>
需要注意的是,网络接口并不存在于Linux的文件系统中,而是定义在内核中的一个str <br>
<br>
ct device的一个数据结构中。每一个device的数据结构都是在驱动的时候创建的,而不像 <br>
字符设备或者块设备那样,即使不存在物理设备也是存在有这个设备文件的。这是在Linu <br>
x 2..2内核版本之后做的改动,在这个版本之前,一旦网络驱动程序被激活,在/dev目录 <br>
下就会出现eth0的文件,对这个设备文件的读写就完成了网络传输;这种做法现在还是用 <br>
在字符设备和块设备上。现在的版本是数据包的发送和接收都是通过直接对接口进行访问 <br>
来完成的。 <br>
对于在系统中的所有网络设备,都是通过一张网络接口管理表dev_base统一进行管理的 <br>
<br>
dev_base指向的struct device的链表,在系统初始化完成之后,系统检测到的所有网络设 <br>
备都将自动的保存在这张链表中,链表中的每一个字节都代表着一个系统检测到的网络设 <br>
备。当系统需要发送数据的时候,网络子系统根据系统路由表选择相应的网络接口进行数 <br>
据传输;而当接收到数据包时,通过驱动程序登记的中断服务程序进行数据的接收(纯软 <br>
件实现的网络设备除外)。 <br>
关于device数据结构和dev_base在5.2.2里面会详细介绍。 <br>
<br>
5.2.2 网络驱动程序中需要用到的重要的数据结构 <br>
5.2.2.1 struct device <br>
这个数据结构是在系统中每一个设备的代表。每一个被系统检测到的网络设备都应该使用 <br>
struct device类型的节点存在于dev_base中。dev_base是内核中存在的外部变量。如果采 <br>
取的是内核检测网卡设备的方式,那么在整个内核没有开始进行网络设备的检测时候,de <br>
v_base中是所有内核可能支持的网络设备的struct device节点;在网络驱动程序检测完之 <br>
后,将不存在的网络设备对应的节点删除,剩下的就是检测到并且得到正确驱动的网络设 <br>
备。具体可以参看下面的图: (假设只存在有lo和eth0设备) <br>
在这个数据结构里面,主要定义的成员变量是init函数指针,这个函数指针初始化为设 <br>
<br>
驱动程序中提供的用来初始化device结构的过程,这个过程实际上就是用来检测和驱动网 <br>
络设备的。在检测进行之前,每一个节点的init函数都指向对应的初始化函数;检测的时 <br>
候对每一个节点都分别调用init函数指针,如果成功返回的话,将该节点保留。 <br>
同时,在这个结构里面还定义了对硬件设备的打开和关闭函数指针(open, close); <br>
<br>
件头的建立函数指针(hard_header);硬件上数据的传输过程(hard_start_xmit)。当 <br>
网络设备打开的时候,就可以通过这个网络设备开始传输数据了,传输出来的数据存放在 <br>
struct sk_buff结构里面(关于这个数据结构,会在5.2.2.2里面介绍)。hard_start_xm <br>
it函数指针是和某一种具体的硬件相关的,通过dev_queue_xmit这个外部函数调用hard_s <br>
tart_xmit函数指针完成网络数据的发送过程。 <br>
<br>
5.2.3 重要的驱动过程 <br>
驱动网络设备驱动程序方法有两种:通过模块驱动和通过内核启动时自动检测的方法。通 <br>
过模块驱动的方法是Linux中使用模块设计的一种方案。我们知道,Linux的内核是将所有 <br>
的支持编译在一起的,并不是微内核技术。如果对Linux内核增加一项功能,就把它的实现 <br>
直接放在内核的代码中。不过为了让Linux的内核体积不至于过于庞大,采用了编译成模块 <br>
的方式。在需要用到这个模块的时候,用shell命令的insmod将该模块插入到内核运行空间 <br>
;如果不需要了,可以用rmmod命令将该模块卸载。insmod触发的是程序里面的init_modu <br>
le()函数;而rmmod命令触发的是cleanup_module()函数。在init_module()函数里面,会 <br>
调用到这种网络设备的init函数指针,如果检测到了这种网络设备,并且初始化成功,那 <br>
么就将这个网络设备对应的device结构插入到dev_base链表里面。 <br>
使用内核启动检测的方法有所不同。在系统启动的时候,内核把所有编译在内河内部支持 <br>
的网卡设备都初始化在一个struct device类型的dev_base链表里面,然后对于每个节点都 <br>
调用自己的init函数指针,如果该函数返回成功,那么该节点对应的设备保留;否则,该 <br>
节点对应的设备不存在,将该节点删除。这样,在系统初始化的最后,剩下来在dev_base <br>
里面的所有节点就全是系统检测到的网络设备了。 <br>
5.2.3.1 模块驱动方法 <br>
在ne.c里面,init_module()函数首先初始化dev设备的init函数指针,然后调用register <br>
_netdev()函数在系统中登记该设备。如果登记成功,那么模块插入成功,否则就返回出错 <br>
信息。在register_netdev()里面,首先检查该网络设备名是否已经确定,如果没有,就赋 <br>
给一个缺省的名称。然后,调用网络设备驱动程序中的init_function,也就是dev->init <br>
函数指针来检测网卡设备是否存在,并且做dev的初始化工作。如果初始化成功,将dev插 <br>
入到dev_base链表的尾部。整个调用流程参看下图: <br>
<br>
<br>
5.2.3.2 内核启动的驱动方法 <br>
内核启动的驱动方法和模块驱动的方法不同,前者要对所有内核支持的网络设备进行检测 <br>
和初始化,而后者只需要检测和初始化被装载的网络设备。为了实现在启动的时候对所有 <br>
可能存在的网络设备都检测一遍,系统会在启动之前将所有支持的网络设备对应的device <br>
结构都挂在dev_base链表上,正如前文所述。然后使用net_dev_init()函数依次对dev_ba <br>
se里面每一个节点都运行init函数指针,如果返回成功,那么该节点对应的设备存在;否 <br>
则就将该节点删除。最后在链表中剩下的所有网络设备都是存在的,并且已经完成了初始 <br>
化。 <br>
这里需要解释一下dev_base的组成,在drivers/net/Space.c里面定义,形成的就是一张由 <br>
device结构组成的链表: <br>
Space.c <br>
670 static struct device eth7_dev = { <br>
671 "eth7", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, eth <br>
if_probe}; <br>
672 static struct device eth6_dev = { <br>
673 "eth6", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð7_dev, et <br>
hif_probe }; <br>
…… <br>
…… <br>
685 static struct device eth0_dev = { <br>
686 "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev, ethif_pro <br>
be };/*eth0进行自动检测*/ <br>
687 <br>
688 # undef NEXT_DEV <br>
689 # define NEXT_DEV (ð0_dev)/*将eth_dev串起来*/ <br>
690 <br>
691 #if defined(SLIP) || defined(CONFIG_SLIP) <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -