ptypebase和ptypeall理解netidreceiveskb函数注解.docx

上传人:b****7 文档编号:25396170 上传时间:2023-06-08 格式:DOCX 页数:7 大小:16.68KB
下载 相关 举报
ptypebase和ptypeall理解netidreceiveskb函数注解.docx_第1页
第1页 / 共7页
ptypebase和ptypeall理解netidreceiveskb函数注解.docx_第2页
第2页 / 共7页
ptypebase和ptypeall理解netidreceiveskb函数注解.docx_第3页
第3页 / 共7页
ptypebase和ptypeall理解netidreceiveskb函数注解.docx_第4页
第4页 / 共7页
ptypebase和ptypeall理解netidreceiveskb函数注解.docx_第5页
第5页 / 共7页
点击查看更多>>
下载资源
资源描述

ptypebase和ptypeall理解netidreceiveskb函数注解.docx

《ptypebase和ptypeall理解netidreceiveskb函数注解.docx》由会员分享,可在线阅读,更多相关《ptypebase和ptypeall理解netidreceiveskb函数注解.docx(7页珍藏版)》请在冰豆网上搜索。

ptypebase和ptypeall理解netidreceiveskb函数注解.docx

ptypebase和ptypeall理解netidreceiveskb函数注解

ptype_base和ptype_all理解,netid_receive_skb()函数注解

在数据包接收过程的那篇笔记中可以知道,在数据包的处理函数netif_receive_skb中,会先看ptype_all中是否有注册的协议,如果有,则调用相应的处理函数,然后再到ptype_base中,找到合适的协议,将skb发送到相关协议的处理函数.比如ip协议(ip_rcv)或者arp(arp_rcv)等等.此篇笔记讲的是有关ptype_all和ptype_base的相关知识点.ptype_base和ptype_all在内核中存储的情况如下图:

可以看到,ptype_base为一个hash表,而ptype_all为一个双向链表.每一个里面注册的协议都用一个structpacket_type表示.structpacket_type

{

unsignedshorttype;/*协议类型*/

structnet_device*dev;

int(*func)(structsk_buff*,structnet_device*,

structpacket_type*);

void*data;/*Privatetothepackettype*/

structpacket_type*next;

};

其中需要注意的是dev参数,此参数表明了协议只处理来自dev指向device的数据,当dev=NULL时,表示该协议处理来自所有device的数据.这样,当注册自己的协议时,就可以指定自己想要监听或者接收的device.

其中注册和注销协议的函数为:

dev_add_pack(...)和dev_remove_pack(...)

这两个函数很简单,分别如下:

voiddev_add_pack(structpacket_type*pt)

{

inthash;

br_write_lock_bh(BR_NETPROTO_LOCK);

#ifdefCONFIG_NET_FASTROUTE

/*Hacktodetectpacketsocket*/

if((pt->data)&&((int)(pt->data)!

=1)){

netdev_fastroute_obstacles++;

dev_clear_fastroute(pt->dev);

}

#endif

if(pt->type==htons(ETH_P_ALL)){

netdev_nit++;

pt->next=ptype_all;

ptype_all=pt;

}else{

hash=ntohs(pt->type)&15;

pt->next=ptype_base[hash];

ptype_base[hash]=pt;

}

br_write_unlock_bh(BR_NETPROTO_LOCK);

}

此函数判断协议类型,然后加到ptype_base或者ptype_all中.

voiddev_remove_pack(structpacket_type*pt)

{

structpacket_type**pt1;

br_write_lock_bh(BR_NETPROTO_LOCK);

if(pt->type==htons(ETH_P_ALL)){

netdev_nit--;

pt1=&ptype_all;

}else{

pt1=&ptype_base[ntohs(pt->type)&15];

}

for(;(*pt1)!

=NULL;pt1=&((*pt1)->next)){

if(pt==(*pt1)){

*pt1=pt->next;

#ifdefCONFIG_NET_FASTROUTE

if(pt->data)

netdev_fastroute_obstacles--;

#endif

br_write_unlock_bh(BR_NETPROTO_LOCK);

return;

}

}

br_write_unlock_bh(BR_NETPROTO_LOCK);

printk(KERN_WARNING"dev_remove_pack:

%pnotfound.\n",pt);

}

此函数也很简单,只是把协议从相关的链表中移除.

下面以ip协议为例子来看看相关的实现:

ip协议结构体的定义如下:

staticstructpacket_typeip_packet_type=

{

__constant_htons(ETH_P_IP),

NULL,/*Alldevices*/

ip_rcv,

(void*)1,

NULL,

};

当ipv4协议栈初始化时,会调用ip_init.之后,所有协议类型为ETH_P_IP的包都会交由ip_rcv处理.代码如下:

void__initip_init(void)

{

dev_add_pack(&ip_packet_type);

ip_rt_init();

inet_initpeers();

#ifdefCONFIG_IP_MULTICAST

proc_net_create("igmp",0,ip_mc_procinfo);

#endif

}

这样在系统启动之后,ip协议便被注册到ptype_base链表中,相应的处理函数为ip_rcv.

arp协议和其他类型的协议(在ptype_base或者ptype_all中的)的执行过程同理.

本人初学网络,水平很菜,如有错误,希望看到的朋友们及时指出,不胜感激.

ps1:

记得刚来实验室的时候,做的截包模块的第一种方法是用的netfilter,第二种方法主要就是用到的这块知识.现在总结起来,觉得还算简单,当初却用了很长时间,想想,真是难者不会,会者不难啊.今天看书的时候,好像又发现了另外一种方法可以实现我的要求,记录在ps2上.

ps2:

在数据链路层截包的另一种方法:

用PF_PACKETsockettype.linux可以用此类型套节字直接从链路层截获或者注入数据.发送数据时,直接发送到dev_queue_xmit.而接收函数时,可以在数据包通过路由之前截获到.如tcpdump和Ethereal都是用到了此套接字.那么总结起来可以看出,截获数据包至少可以有三种方法实现,第一种的netfilter是在协议栈中截获数据包,而利用ptype_all或者ptype_base和后面这种套节字的方法是在链路层截获数据包.//当网络设备收到网络数据包时,最终会在软件中断环境里调用此函数//当网络设备收到网络数据包时,最终会在软件中断环境里调用此函数

 

[cpp]viewplaincopyprint?

intnetif_receive_skb(structsk_buff*skb)

{

//ptype_all用于sniffer这样的程序

//发送一份拷贝给这些注册的sniffer程序

list_for_each_entry_rcu(ptype,&ptype_all,list){

if(!

ptype->dev||ptype->dev==skb->dev){

if(pt_prev)

ret=deliver_skb(skb,pt_prev,orig_dev);

pt_prev=ptype;

}

}

//内核编译开Bridge_config,则将该数据包让网桥函数来处理,否则handle_bridge定义为空操作,

//返回skb,让协议栈来处理上层协议。

skb=handle_bridge(skb,&pt_prev,&ret,orig_dev);

if(!

skb)

gotoout;

skb=handle_macvlan(skb,&pt_prev,&ret,orig_dev);

if(!

skb)

gotoout;

//对该数据包转达到其他L3协议的处理函数

type=skb->protocol;

list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&15],list){

if(ptype->type==type&&

(!

ptype->dev||ptype->dev==skb->dev)){

if(pt_prev)

ret=deliver_skb(skb,pt_prev,orig_dev);

pt_prev=ptype;

}

}

}intnetif_receive_skb(structsk_buff*skb)

{

//ptype_all用于sniffer这样的程序

//发送一份拷贝给这些注册的sniffer程序

list_for_each_entry_rcu(ptype,&ptype_all,list){

if(!

ptype->dev||ptype->dev==skb->dev){

if(pt_prev)

ret=deliver_skb(skb,pt_prev,orig_dev);

pt_prev=ptype;

}

}

//内核编译开Bridge_config,则将该数据包让网桥函数来处理,否则handle_bridge定义为空操作,

//返回skb,让协议栈来处理上层协议。

skb=handle_bridge(skb,&pt_prev,&ret,orig_dev);

if(!

skb)

gotoout;

skb=handle_macvlan(skb,&pt_prev,&ret,orig_dev);

if(!

skb)

gotoout;

//对该数据包转达到其他L3协议的处理函数

type=skb->protocol;

list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&15],list){

if(ptype->type==type&&

(!

ptype->dev||ptype->dev==skb->dev)){

if(pt_prev)

ret=deliver_skb(skb,pt_prev,orig_dev);

pt_prev=ptype;

}

}

}netif_receive_skb()的主要作用体现在两个遍历链表的操作中,其中之一为遍历ptype_all链,这些为注册到内核的一些sniffer,将上传给这些sniffer,另一个就是遍历ptype_base,这个就是具体的协议类型。

当eth1接收到一个IP数据包时,它首先分别发送一份副本给每个ptype_all链表中的packet_type,它们都由package_rcv处理,然后再根据HASH值,在遍历另一个HASH表时,发送一份给类型为ETH_P_IP的类型,它由ip_rcv处理。

如果这个链中还注册有其它IP层的协议,它也会同时发送一个副本给它。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 销售营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1