乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      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)達(dá)到其他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)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多