📄 (ldd) ch14-网络驱动程序(上)(转载).txt
字号:
plip和ppp一类点到点协议使用这个域记录连接另一侧的IP号码。和前面的域一样,它也
是只读的。
是只读的。
unsigned short flags;
接口标志。这个域含有下列位值。前缀IFF意为接口标志(InterFace Flags)。有些标
志由核心管理,有些则是在初始化时由接口设置,以确认接口的能力。有效的标志是:
IFF_UP
当接口是活跃的时,核心置上该标志。这个标志对驱动程序是只读的。
IFF_BROADCAST
这个标志表明接口的播送地址是有效的。以太网卡支持播送。
IFF_DEBUG
查错模式。这标志控制printk调用的唠叨,还用在其它一些查错目的。尽管目前没有官
方驱动程序使用它,用户程序可以通过ioctl来对其置位或者清除,你的驱动程序可以使
用它。misc-progs/netifdebug程序可以用来将这个标志打开或关闭。
IFF_LOOPBACK
这个标志在环回接口中要被置位。核心检测这个标志而不是将名字lo作为特殊接口硬写
入程序。
IFF_POINTOPOINT
点到点的初始化函数应置位这个标志。例如,plip对它置位。ifconfig工具也可以对其
置位和清除。当它被置位时,dev->pa_dstaddr应该指向连接的另一端。
IFF_NOARP
常规网络接口可以传送ARP包。如果接口不能进行ARP,它必须置这个标志。例如,点到
点接口并不需要运行ARP,它只能增加额外的通信,却不能获取任何有用的信息。snull
不具有ARP能力,因此它要对其置位。
IFF_PROMISC
这个标志被置位以获得杂类操作。在缺省情况下,以太网接口使用硬件过滤器以保证它
只收到播送包和指向其硬件地址的包。而象tcpdump一类包监视器则在接口上设置杂类模
式,以获取经过接口传输介质的所有包。
IFF_MULTICAST
能进行选播传送的接口要置这个标志。ether_setup在缺省情况下对其置位。所以如果你
的驱动程序不支持选播,它必须在初始化时清除这个标志。
IFF_ALLMULTI
这个标志告诉接口接收所有的选播包。只有当IFF_MULTICAST被置位,而主机由进行选播
路由时,核心对其置位。它对接口时只读的。IFF_MULTICAST和IFF_ALLMULTI早在1.2版
就已经定义了,但那时并未使用。在后面“选播”一节我们将看到它是如何使用的。
IFF_MASTER
IFF_SLAVE
这些标志被加载均衡代码使用。接口驱动程序不需要知道它们。
IFF_NOTRAILERS
IFF_RUNNING
这些标志在Linux中不使用,只是为了和BSD兼容而存在。
当一个程序改变IFF_UP,open和close方法会被调用。当IFF_UP或其它标志被修改时,se
当一个程序改变IFF_UP,open和close方法会被调用。当IFF_UP或其它标志被修改时,se
t_multicast_list方法被调用。如果驱动程序因为标志的修改而要执行一些动作,那么
必须在set_multicast_list中进行。例如,当IFF_PROMIS被置位或清除时,板上硬件过
滤器必须被通知。这个设备方法的责任将在后面的“选播”一节简单介绍。
设备方法
与字符设备和块设备的情况一样,每个网络设备要声明在其上操作的函数。可以在网络
接口上进行的操作列在下面。一些操作可以留为NULL,还有一些通常不去动它们,因为e
ther_setup给它们分配合适的方法。
一个网络接口的设备方法可以分为两类:基本的和可选的。基本的包括那些为访问接口
所需要的;可选的方法实现一些并不严格要求的高级功能。下面是基本方法:
int (*open)(struct device *dev);
打开接口。只要ifconfig激活一个接口,它就被打开了。open方法要注册它需要的所有
资源(I/O端口,IRQ,DMA,等),打开硬件,增加模块的使用计数。
int (*stop)(struct device *dev);
终止接口。接口在关闭时就终止了;在打开时进行的操作应被保留。
int (*hard_start_xmit)(struct sk_buff *skb, struct device *dev);
硬件开始传送。这个方法请求一个包的传送。这个包含在一个套接字缓冲区结构(sk_bu
ff)中。套接字缓冲区在下面介绍。
int (*rebuild_header)(void *buf, struct device *dev, unsigned long raddr,
struct sk_buffer *skb);
这个函数用来在一个包传送之前重构硬件包头。这个以太网设备使用的缺省包头用ARP向
包中填入缺少的信息。snull驱动程序实现了它自己的这个方法,因为ARP并不在sn接口
上运行。(在本章的后面会介绍ARP。)这个方法的参数是一些指针,分别指向硬件包头
,设备,“路由器地址”(包的初始目的地),以及被传送的缓冲区。
int (*hard_header)(struct sk_buffer *skb, struct device *dev, unsigned
short type,
void *daddr, void *saddr, unsigned len);
硬件包头。这个函数用以前获取的源和目的地址构造包头;它的任务是组织那些以参数
的形式传给它的信息。eth_header是以太网类接口的缺省函数, ether_setup相应地对
的形式传给它的信息。eth_header是以太网类接口的缺省函数, ether_setup相应地对
这个域赋值。给出的参数顺序适用于核心2.0或更高版本,但与1.2有所不同。这个改变
对以太网驱动程序是透明的,因为它继承了 eth_header的实现;其它驱动程序可能要处
理一下这个不同,如果它们想保持向后兼容的话。
struct enet_statistics * (*get_stats)(struct device *dev);
当应用希望获得接口的统计信息时需要调用这个方法,例如,当运行ifconfig或netstat
–i时。在snull中的一个示例实现将在后面“统计信息”中介绍。
int (*set_config)(struct device *dev, struct ifmap *map);
改变接口的配置。这个方法是配置驱动程序的入口点。设备的I/O地址和中断号可以在运
行时用set_config改变。在接口不能探测到时,系统管理员可以适用这个能力。这个方
法在后面的“运行时配置”中介绍。
其余的设备方法是被我称为可选的那些。传递给其中一些的参数在Linux1.2到Linux2.0
的转变中改了好几次。如果你想写一个可以在两个版本核心都工作的驱动程序,你可以
只为从2.0开始的版本实现这些操作。
int (*do_ioctl)(struct devices *dev, struct ifreg *ifr, int cmd);
int (*do_ioctl)(struct devices *dev, struct ifreg *ifr, int cmd);
执行接口特定的ioctl命令。这些命令的实现在后面的“自定义ioctl命令”中描述。这
里给出的原形在1.2以上的核心都能工作。如果接口不需要任何接口特定的命令,那么结
构device中相应的域可以留为NULL。
void (*set_multicast_list)(struct device *dev);
当设备的选播列表改变和标志改变时,将调用这个方法。这里的参数传递与1.2版本不同
。更多的细节和一个示例实现见“选播”一节。
int (*set_mac_address)(struct device *dev, void *addr);
如果接口支持改变硬件地址的能力,可实现这个函数。多数接口要么不支持这个能力,
要么使用缺省的eth_mac_addr实现。这个原形与1.2版也不同。
#define HAVE_HEADER_CACHE
void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev,
unsigned short htype, __u32 daddr);
void (*header_cache_update)(struct hh_cache *hh, struct device *dev,
unsigned char *haddr);
unsigned char *haddr);
这些函数和宏在Linux1.2中没有。以太网驱动程序不必关心header_cache的问题,因为e
th_setup会安排使用缺省的方法。
#define HAVE_CACHE_MTU
int (*change_mtu)(struct device *dev, int new_mtu);
如果接口的MTU(最大传送单元)发生了改变,这个函数负责采取动作。这个函数和宏在
Linux1.2中都没有。当MTU改变时,如果驱动程序要做一些特殊的事情,它应该声明它自
己的函数,不然将由缺省函数来完成。如果你感兴趣,snull有一个这个函数的模版。
工具域
其余的结构device中的域被接口用来保存一些有用的状态信息。其中一些被ifconfig和n
etstat用来向用户提供当前配置的信息。因此,接口应该对这些域赋值。
unsigned long trans_start;
unsigned long last_rx;
unsigned long last_rx;
这两个域用来保存一些瞬间值。它们目前不用,但核心有可能将来使用这些计时提示。
驱动程序负责在传送开始时和收到包时更新这些值。trans_start域还可以被驱动程序用
来检测锁定。驱动程序可以在等待一个“传送完成”的中断时用trans_start来检查超时
。
void *priv
等价于filp->private_data。驱动程序拥有这个指针,可以随意使用。通常这个私有数
据结构含有一个enet_statistics结构项。这个域在以前的“初始化每个设备”中用过。
unsigned char if_prot;
这个域用来记录哪个硬件端口被接口使用(例如,BNC,AUI,TP)。任何数值都可以按
需要赋给它。
unsigned char dma;
被接口使用的DMA通道。这个域被ioctl的SIOCGIFMAP命令使用。
struct dev_mc_list *mc_list;
unsigned char dma;
被接口使用的DMA通道。这个域被ioctl的SIOCGIFMAP命令使用。
struct dev_mc_list *mc_list;
int mc_count
这两个域被用来处理选播传送。Mc_count是mc_list中项的个数。更多的细节见“选播”
结构device中还有一些别的域,但驱动程序没有使用它们
--
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -