岁月联盟 - 技术社区 - BBS.SYUE.COM's Archiver

猪猪 发表于 2007-1-28 16:29

关于ptype_all链表和pypte_base的理解

麻烦了yawl和scz几次后我才稍微了解一点关于ptype_all链表和ptype_base数组,后头再看看yawl
的“导读0.2”,发现
原来yawl讲的还是每句都有道理的。只是对于我这样初级阶段的来说还是要搞这么久才明白。

下面的内容都是在大家的帮助下我的理解,如有理解错误希望大家及时指出,希望不要误导他人。
如果侥幸说对,希望对初学者
有所帮助。

(首先声明我所看的是redhat6.2的kernel 2.2.14 工具是lxr)
关于ptype_all链表,一般情况下是空的(其实是翻译,见dev.c:944 The ptype_all list of
taps (normally empty)

先看ptype_base,ptype_base数组包含了包括ip,x25等一系列协议类型,说ptype_base不得不说?br>絛ev_add_pack函数
ptype_all链表和ptype_base数组的构建都是由此函数执行的。

见dev.c文件

205 if(pt->type==htons(ETH_P_ALL))#如果是ETH_P_ALL将其加到ptype_all链表中
206 {
207 netdev_nit++;
208 pt->next=ptype_all;
209 ptype_all=pt;
210 }
211 else #如果不是,模15后加到ptype_base数组中,此数组相当于hash链表
212 {
213 hash=ntohs(pt->type)&15;
214 pt->next = ptype_base[hash];
215 ptype_base[hash] = pt;

见网络初始化main.c中
sock_init()----proto_init()中pro->init_func()实际调的是各个协议的初始化
只列出常用的
103 struct net_proto protocols[] = {
108 #ifdef CONFIG_PACKET
109 { "PACKET", packet_proto_init },
110 #endif
111
112 #ifdef CONFIG_UNIX
113 { "UNIX", unix_proto_init }, /* Unix domain socket family */
114 #endif
142 { "INET", inet_proto_init }, /* TCP/IP */
143 #ifdef CONFIG_IPV6
144 { "INET6", inet6_proto_init}, /* IPv6 */
145 #endif
172 { NULL, NULL } /* End marker */
173 };

tcp/ip调的自然是inet_proto_init,其中调用函数ip_init()而ip_init中调的是dev_add_pack

ip_output.c
980 __initfunc(void ip_init(void))
981 {
982 dev_add_pack(&ip_packet_type);#将ip_packet_type加到ptype_base数组中
同样x25会在x25_proto_init中调用dev_add_pack(x25_packet_type)加入ptype_base数组
通过分析我们知道,在系统初启,网络初始化后系统中ptype_all这时是空的,而ptype_base中加?br>肓讼低乘?兄С值?br>所有协议的packet_type,例如ip协议的见下面的结构

ip_output.c
954 static struct packet_type ip_packet_type =
955 {
956 __constant_htons(ETH_P_IP),
957 NULL, /* All devices */
958 ip_rcv,
959 NULL,
960 NULL,
961 };
当系统调用net_bh时,当数据是ip协议时自然在pt_prev->func(skb, skb->dev, pt_prev);
时调用了ip_rcv,(见yawl的“导读v0.2”)
这是一般情况,我们看到在用到ptype_base前有
dev.c
949 for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
net_bh函数在使用ptype_base前,先用的是ptype_all,一直没讨论ptype_all。只有在调用dev_ad
d_pack
type为ETH_P_ALL时,才会将packet_type加到ptype_all中,查了系统所有文件发现只有当构建一?br>鰏ocket
用PF_PACKET同时用ETH_P_ALL是会将一个packet_type加到ptype_all中,如scz所说当开两个sniff
er时,
自然ptype_all链表会有两项,其实这个链表正是一个hook的好例子,这样系统受到的所有的包都?br>?籶type_all
截获,其实在建PF_SOCKET的socket时,不一定用ETH_P_ALL,用ETH_P_IP时,可以看到它被加到pt
ype_base
中,所以在有ip包到达时数据即到系统的packet_type,也到自己建的packet_type中,看到这里我
才觉得
对原来scz的关于建socket用什么type的文章有所理解。




看起来会很乱的


struct packet_type *               struct packet_type              
       ptype_base                          ip_packet_type            
          +-----+                               +---------------------+           
          | 0   |------------------------------>|                     |         
          |------|                                |  ETH_P_IP()   |      
          |------|                                |                     |            
          |------|                                |---------------------|         
          |------|                                |                     |      
          |------|                                |NULL              |      
          |------|                                |---------------------|           
          |------|                                |                     |           
          |------|                                |ip_rcv ()         |           
          |------|                                |---------------------|         
          |------|                                |                     |           
          |------|                                |NULL              |         
          |------|                                |---------------------|        
          |------|                                |                     |            
          |------|                                |NULL              |            
          |------|                               +---------------------+      
          |------|                               struct packet_type               
          |      |                                     arp_packet_type               
          |------|                         +-----------------------+               
          | 6   |----------------------->|                        |            
          |------|                         |ETH_P_ARP       |            
          |------|                         |------------------------|                    
          |------|                         |                        |         
          |------|                         |NULL                 |                 
          |------|                         |------------------------|              
          |------|                         |                        |               
          +-----+                        |arp_rcv()            |                          
                                           |-------------------------|                           
                                           |                         |                             
                                           |NULL                  |               
                                           |-------------------------|            
                                           |                         |                           
                                           |NULL                  |              
                                           +-------------------------+                                 

struct packet_type *                          
         ptype_all=NULL

初始化的时候为空。用于指向Eth_P_ALL类型的packet_type结构。

注册在这里的接收函数,可以收到所以的数据包,包括incomming,  output,forward。

并且收到的是一个clone的数据包,也就是说  在这里处理的过程会影响到后面的处理过程。

dev_add_pack就是如上根据类型加到不同的链表中。注册自己的接收函数的。 这个dev_add_pack的确是某些人比较喜欢的东西,呵呵

页: [1]

Powered by Discuz! Archiver 7.0.0  © 2001-2009 Comsenz Inc.