kernel:linux-2.6.18
Packet_type数据结构包含协议类型、指向网络设备的指针、指向协议的接收数据处理例程的指针等。
结构体:
-
struct packet_type {
-
__be16 type; /* This is really htons(ether_type). */
-
struct net_device *dev; /* NULL is wildcarded here */
-
int (*func) (struct sk_buff *,
-
struct net_device *,
-
struct packet_type *,
-
struct net_device *);
-
struct sk_buff *(*gso_segment)(struct sk_buff *skb,
-
int features);
-
int (*gso_send_check)(struct sk_buff *skb);
-
void *af_packet_priv;
-
struct list_head list;
-
};
定义:
-
static struct list_head ptype_base[16]; /* 16 way hashed list */
-
static struct list_head ptype_all; /* Taps */
ptype_all为一个双向链表。Ptype_base是一个哈希表,其哈希函数以协议标识符为参数,内核通常利用该哈希表判断应当接受传入的网络数据报的协议。
初始化:
-
INIT_LIST_HEAD(&ptype_all);
-
for (i = 0; i < 16; i++)
-
INIT_LIST_HEAD(&ptype_base[i]);
在Linux进行网络层的初始化时,每个协议要在ptype_all链表或ptype_base哈希表中以packet_type数据结构通过dev_add_pack函数进行注册和dev_remove_pack进行删除。
操作:
-
void dev_add_pack(struct packet_type *pt)
-
{
-
int hash;
-
-
spin_lock_bh(&ptype_lock);
-
//如果是ETH_P_ALL将其加到ptype_all链表中
-
if (pt->type == htons(ETH_P_ALL)) {
-
netdev_nit++;
-
list_add_rcu(&pt->list, &ptype_all);
-
} else {
-
hash = ntohs(pt->type) & 15;
-
list_add_rcu(&pt->list, &ptype_base[hash]);
-
}
-
spin_unlock_bh(&ptype_lock);
-
}
-
void __dev_remove_pack(struct packet_type *pt)
-
{
-
struct list_head *head;
-
struct packet_type *pt1;
-
-
spin_lock_bh(&ptype_lock);
-
-
if (pt->type == htons(ETH_P_ALL)) {
-
netdev_nit--;
-
head = &ptype_all;
-
} else
-
head = &ptype_base[ntohs(pt->type) & 15];
-
-
list_for_each_entry(pt1, head, list) {
-
if (pt == pt1) {
-
list_del_rcu(&pt->list);
-
goto out;
-
}
-
}
-
-
printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
-
out:
-
spin_unlock_bh(&ptype_lock);
-
}
ARP协议进行注册流程:
ARP协议结构体:
-
static struct packet_type arp_packet_type = {
-
.type = __constant_htons(ETH_P_ARP),
-
.func = arp_rcv,
-
};
-
arp_init()初始化,把arp_packet_type加入到ptype_base。
-
void __init arp_init(void)
-
{
-
neigh_table_init(&arp_tbl);
-
dev_add_pack(&arp_packet_type);
-
arp_proc_init();
-
register_netdevice_notifier(&arp_netdev_notifier);
-
}
当协议类型为ETH_P_ARP的数据都会交由arp_rcv处理.在netif_receive_skb函数中,有ptype_all和ptype_base的调用.
-
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;
-
}
-
}
-
-
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;
-
}
-
}
deliver_skb函数实现packet_type结构体中func函数指针调用:
-
static __inline__ int deliver_skb(struct sk_buff *skb,
-
struct packet_type *pt_prev,
-
struct net_device *orig_dev)
-
{
-
atomic_inc(&skb->users);
-
//如果type==ETH_P_ARP,就会调用arp_rcv函数(pt_prev->func指向arp_rcv函数)。
-
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
-
}
-
阅读(3974) | 评论(0) | 转发(2) |