小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

ptype_base和ptype_all理解,netid_receive_skb()函數(shù)注解

 A_Geek 2013-07-20

在數(shù)據(jù)包接收過程的那篇筆記中可以知道,在數(shù)據(jù)包的處理函數(shù)netif_receive_skb中,會先看ptype_all中是否有注冊的協(xié)議,如果有,則調(diào)用相應(yīng)的處理函數(shù),然后再到ptype_base中,找到合適的協(xié)議,將skb發(fā)送到相關(guān)協(xié)議的處理函數(shù).比如ip協(xié)議(ip_rcv)或者arp(arp_rcv)等等.此篇筆記講的是有關(guān)ptype_all和ptype_base的相關(guān)知識點.

ptype_base和ptype_all在內(nèi)核中存儲的情況如下圖:



可以看到,ptype_base為一個hash表,而ptype_all為一個雙向鏈表.每一個里面注冊的協(xié)議都用一個struct packet_type表示.

struct packet_type
{
unsigned short type; /*協(xié)議類型*/
struct net_device *dev;
int (*func) (struct sk_buff *, struct net_device *,
struct packet_type *);
void *data; /* Private to the packet type */
struct packet_type *next;
};
其中需要注意的是dev參數(shù),此參數(shù)表明了協(xié)議只處理來自dev指向device的數(shù)據(jù),當(dāng)dev=NULL時,表示該協(xié)議處理來自所有device的數(shù)據(jù).這樣,當(dāng)注冊自己的協(xié)議時,就可以指定自己想要監(jiān)聽或者接收的device.
其中注冊和注銷協(xié)議的函數(shù)為:
dev_add_pack(...)和dev_remove_pack(...)
這兩個函數(shù)很簡單,分別如下:
void dev_add_pack(struct packet_type *pt)
{
int hash;
br_write_lock_bh(BR_NETPROTO_LOCK);
#ifdef CONFIG_NET_FASTROUTE
/* Hack to detect packet socket */
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);
}
此函數(shù)判斷協(xié)議類型,然后加到ptype_base或者ptype_all中.
void dev_remove_pack(struct packet_type *pt)
{
struct packet_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;
#ifdef CONFIG_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: %p not found.\n", pt);
}
此函數(shù)也很簡單,只是把協(xié)議從相關(guān)的鏈表中移除.
下面以ip協(xié)議為例子來看看相關(guān)的實現(xiàn):
ip協(xié)議結(jié)構(gòu)體的定義如下:
static struct packet_type ip_packet_type =
{
__constant_htons(ETH_P_IP),
NULL, /* All devices */
ip_rcv,
(void*)1,
NULL,
};
當(dāng)ipv4協(xié)議棧初始化時,會調(diào)用ip_init.之后,所有協(xié)議類型為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
}
這樣在系統(tǒng)啟動之后,ip協(xié)議便被注冊到ptype_base鏈表中,相應(yīng)的處理函數(shù)為ip_rcv.
arp協(xié)議和其他類型的協(xié)議(在ptype_base或者ptype_all中的)的執(zhí)行過程同理.
本人初學(xué)網(wǎng)絡(luò),水平很菜,如有錯誤,希望看到的朋友們及時指出,不勝感激.
ps1:記得剛來實驗室的時候,做的截包模塊的第一種方法是用的netfilter,第二種方法主要就是用到的這塊知識.現(xiàn)在總結(jié)起來,覺得還算簡單,當(dāng)初卻用了很長時間,想想,真是難者不會,會者不難啊.今天看書的時候,好像又發(fā)現(xiàn)了另外一種方法可以實現(xiàn)我的要求,記錄在ps2上.
ps2:在數(shù)據(jù)鏈路層截包的另一種方法:用PF_PACKET socket type.linux可以用此類型套節(jié)字直接從鏈路層截獲或者注入數(shù)據(jù).發(fā)送數(shù)據(jù)時,直接發(fā)送到dev_queue_xmit.而接收函數(shù)時,可以在數(shù)據(jù)包通過路由之前截獲到.如tcpdump和Ethereal都是用到了此套接字.那么總結(jié)起來可以看出,截獲數(shù)據(jù)包至少可以有三種方法實現(xiàn),第一種的netfilter是在協(xié)議棧中截獲數(shù)據(jù)包,而利用ptype_all或者ptype_base和后面這種套節(jié)字的方法是在鏈路層截獲數(shù)據(jù)包.


  1. //當(dāng)網(wǎng)絡(luò)設(shè)備收到網(wǎng)絡(luò)數(shù)據(jù)包時,最終會在軟件中斷環(huán)境里調(diào)用此函數(shù)
  1. int netif_receive_skb(struct sk_buff *skb)
  2. {
  3. //ptype_all 用于sniffer這樣的程序
  4. // 發(fā)送一份拷貝給這些注冊的sniffer程序
  5. list_for_each_entry_rcu(ptype, &ptype_all, list) {
  6. if (!ptype->dev || ptype->dev == skb->dev) {
  7. if (pt_prev)
  8. ret = deliver_skb(skb, pt_prev, orig_dev);
  9. pt_prev = ptype;
  10. }
  11. }
  12. // 內(nèi)核編譯開Bridge_config,則將該數(shù)據(jù)包讓網(wǎng)橋函數(shù)來處理,否則handle_bridge定義為空操作,
  13. // 返回skb,讓協(xié)議棧來處理上層協(xié)議。
  14. skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
  15. if (!skb)
  16. goto out;
  17. skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
  18. if (!skb)
  19. goto out;
  20. //對該數(shù)據(jù)包轉(zhuǎn)達到其他L3協(xié)議的處理函數(shù)
  21. type = skb->protocol;
  22. list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
  23. if (ptype->type == type &&
  24. (!ptype->dev || ptype->dev == skb->dev)) {
  25. if (pt_prev)
  26. ret = deliver_skb(skb, pt_prev, orig_dev);
  27. pt_prev = ptype;
  28. }
  29. }
  30. }

netif_receive_skb()的主要作用體現(xiàn)在兩個遍歷鏈表的操作中,其中之一為遍歷ptype_all 鏈,這些為注冊到內(nèi)核的一些 sniffer,將上傳給這些sniffer,另一個就是遍歷 ptype_base,這個就是具體的協(xié)議類型。當(dāng) eth1 接收到一個IP數(shù)據(jù)包時,它首先分別發(fā)送一份副本給每個 ptype_all 鏈表中的 packet_type,它們都由 package_rcv 處理,然后再根據(jù)HASH 值,在遍歷另一個HASH 表時,發(fā)送一份給類型為 ETH_P_IP 的類型,它由 ip_rcv處理。如果這個鏈中還注冊有其它 IP層的協(xié)議,它也會同時發(fā)送一個副本給它。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多