分析这个函数之前先看看struct packet_type 这个结构体,ptype_all和ptype_base这两个链表 :
点击(此处)折叠或打开
-
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 *); //在这里注册三层回调函数,例如ip_rcv, arp_rcv等
-
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 */
INIT_LIST_HEAD(&ptype_all); //在net_dev_init函数中进行了初始化
for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&ptype_base[i]);
/*
* IP protocol layer initialiser
*/
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
.gso_send_check = inet_gso_send_check,
.gso_segment = inet_gso_segment,
};
void dev_add_pack(struct packet_type *pt)
{
int hash;
spin_lock_bh(&ptype_lock);
if (pt->type == htons(ETH_P_ALL)) { //抓包软件定义的类型为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]); //根据协议类型进行哈希挂在ptype_base数组中,
}
spin_unlock_bh(&ptype_lock);
}
dev_add_pack(&ip_packet_type); //在inet_init初始化函数中我们ip协议packet_type结构根据ETH_P_IP类型挂在了ptype_base数组中。在netif_receive_skb函数中我们根据
//收到数据包的类型为索引来遍历ptype_base数组,找到挂接的ip协议类型,然后就能把数据包交给注册的L3回调函数ip_rcv来处理了
//我们可以推测像其他协议appTalk等也会有相应的操作,如果收到的数据包的类型是appTalk,那么会交个appTalk注册的回调函数
虽然我们没有看wireshark,tcpdump这些抓包函数具体代码,但是一定就是这么干的。其实我们从netif_receive_skb函数中可以看到ptype_all这个链表就为我网络嗅探器准备的。
点击(此处)折叠或打开
-
int netif_receive_skb(struct sk_buff *skb)
-
{
-
struct packet_type *ptype, *pt_prev;
-
struct net_device *orig_dev;
-
int ret = NET_RX_DROP;
-
__be16 type;
-
-
/* if we've gotten here through NAPI, check netpoll */
-
if (skb->dev->poll && netpoll_rx(skb)) //如果打开了netpoll,像netconsole,数据包就直接被勾走了
-
return NET_RX_DROP;
-
-
if (!skb->tstamp.off_sec)
-
net_timestamp(skb);
-
-
if (!skb->iif)
-
skb->iif = skb->dev->ifindex;
-
-
orig_dev = skb_bond(skb); //这个应该和多网卡绑定有关
-
-
if (!orig_dev)
-
return NET_RX_DROP;
-
-
__get_cpu_var(netdev_rx_stat).total++;
-
-
skb->h.raw = skb->nh.raw = skb->data;
-
skb->mac_len = skb->nh.raw - skb->mac.raw;
-
-
pt_prev = NULL;
-
-
rcu_read_lock();
-
-
#ifdef CONFIG_NET_CLS_ACT
-
if (skb->tc_verd & TC_NCLS) {
-
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
-
goto ncls;
-
}
-
#endif
-
-
-
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;
-
}
-
}
-
-
-
#ifdef CONFIG_NET_CLS_ACT
-
if (pt_prev) {
-
ret = deliver_skb(skb, pt_prev, orig_dev);
-
pt_prev = NULL; /* noone else should process this after*/
-
} else {
-
skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
-
}
-
-
ret = ing_filter(skb);
-
-
if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
-
kfree_skb(skb);
-
goto out;
-
}
-
-
skb->tc_verd = 0;
-
ncls:
-
#endif
-
-
if (handle_bridge(&skb, &pt_prev, &ret, orig_dev)) //如果打开了桥, 就进入桥处理函数进行处理
-
goto out;
-
-
type = skb->protocol; //ip 0x0800 arp 0x0806 loopback 0x0060
-
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { //遍历第二个链表,这是个数组,索引是skb->protocol
-
if (ptype->type == type &&
-
(!ptype->dev || ptype->dev == skb->dev)) {
-
if (pt_prev)
-
ret = deliver_skb(skb, pt_prev, orig_dev);
-
pt_prev = ptype;
-
}
-
}
-
-
if (pt_prev) {
-
ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); //调用根据注册的函数进行处理
-
} else {
-
kfree_skb(skb);
-
/* Jamal, now you will not able to escape explaining
-
* me how you were going to use this. :-)
-
*/
-
ret = NET_RX_DROP;
-
}
-
-
out:
-
rcu_read_unlock();
-
return ret;
- }