ptype_base/ptype_all(内核2.6.32)
来源:互联网 发布:计算机视觉常用算法 编辑:程序博客网 时间:2024/05/18 01:06
ptype_base和ptype_all在内核中存储的情况如下图:
可以看到,ptype_base为一个hash表,而ptype_all为一个双向链表.每一个里面注册的协议都用一个struct packet_type表示.
struct packet_type
{
unsigned short type; /*协议类型*/
struct net_device *dev; /* 如果为null则表示接受所有的设备 */
int (*func) (struct sk_buff *, struct net_device *,
struct packet_type *);
struct sk_buff*(*gso_segment)(struct sk_buff *,skb int features);
int (*gso_send_check)(struct sk_buff *skb);
struct sk_buff**(*gro_receive)(struct sk_buff **head, struct sk_buff *skb);
int (*gro_complete)(struct sk_buff *skb);
void *af_packet_priv;
struct list_head list;
};
其中需要注意的是dev参数,此参数表明了协议只处理来自dev指向device的数据,当dev=NULL时,表示该协议处理来自所有device的数据.这样,当注册自己的协议时,就可以指定自己想要监听或者接收的device.
其中注册和注销协议的函数为:
dev_add_pack(...)和dev_remove_pack(...)
这两个函数很简单,分别如下:
void dev_add_pack(struct packet_type *pt)
{
int hash;
spin_lock_bh(&pt->lock);
if (pt->type == htons(ETH_P_ALL)) {
list_add_rcu(&pt->list, &ptype_all)
} else {
hash = ntohs(pt->type) & PTYPE_HASH_MASK;
list_add_rcu(&pt->list, &ptype_base[hash]);
}
spin_unlock_bh(&pt->lock);
}
此函数判断协议类型,然后加到ptype_base或者ptype_all中.
void dev_remove_pack(struct packet_type *pt)
{
struct packet_type *pt1;
spin_lock_bh(&pt->lock);
if (pt->type == htons(ETH_P_ALL)) {
head = &ptype_all;
} else {
pt1=&ptype_base[ntohs(pt->type)& PTYPE_HASH_MASK];
}
list_for_each_entry(pt1, head, list)
{
if (pt == pt1)
{
list_del_rcu(&pt->list);
goto out;
}
}
spin_unlock_bh(&ptype->lock);
}
此函数也很简单,只是把协议从相关的链表中移除.
下面以ip协议为例子来看看相关的实现:
ip协议结构体的定义如下:
static struct packet_type ip_packet_type =
{
__constant_htons(ETH_P_IP),
NULL, /* All devices */
ip_rcv,
(void*)1,
NULL,
};
当ipv4协议栈初始化时,会调用ip_init.之后,所有协议类型为ETH_P_IP的包都会交由ip_rcv处理.代码如下:
void __init ip_init(void)
{
dev_add_pack(&ip_packet_type);
ip_rt_init();
inet_initpeers();
#ifdef CONFIG_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_PACKET socket type.linux可以用此类型套节字直接从链路层截获或者注入数据.发送数据时,直接发送到dev_queue_xmit.而接收函数时,可以在数据包通过路由之前截获到.如tcpdump和Ethereal都是用到了此套接字.那么总结起来可以看出,截获数据包至少可以有三种方法实现,第一种的netfilter是在协议栈中截获数据包,而利用ptype_all或者ptype_base和后面这种套节字的方法是在链路层截获数据包.
- ptype_base/ptype_all(内核2.6.32)
- 关于ptype_all和pypte_base中的pt_prev的说明
- Linux 内核 2.6.32 发布
- Linux-2.6.32内核移植
- linux内核升级到2.6.32
- 2.6.32内核的generic_make_request()解读
- linux-2.6.32内核LCD驱动移植
- 2.6.32内核sendfile的两个bug
- linux kernel 2.6.32内核代码注释
- 关于2.6.32内核bus_id的问题
- linux-2.6.32内核LCD驱动移植
- centos 内核升级(2.6.32->3.19.0)
- keepalived安装 (2.6.32内核)
- 2.6内核以上不重编内核增加内核模块
- 将Ubuntu 10.04自带2.6.32内核升级成3.0内核图文教程
- Linux 2.6内核编译,内核升级
- 读书笔记----从内核出发(2.6内核)
- 2.6内核的内核抢占机制
- 扩展jtree的功能
- C#高性能大容量SOCKET并发(三):接收、发送
- FIO的安装、使用与分析
- “压缩感知” 之 “Hello World”
- C++ socket
- ptype_base/ptype_all(内核2.6.32)
- WebBrowser控件禁用超链转向、脚本错误提示、默认右键菜单等
- 现今评论最好的objective-c的书 2013-12-25
- System.getProperty()参数大全
- C#中的Delegate
- c#MQ简单操作
- cocos2d-x 数学函数、常用宏整理(2)
- eclipse.ini内存设置
- hbase java 实例