zoukankan      html  css  js  c++  java
  • Linux网络协议栈(四)——链路层(2)

    2、协议相关
    2.1、第3层协议的管理
    在Linux内核中,有两种不同目的的3层协议:
    (1)    ptype_all管理的协议主要用于分析目的,它接收所有到达第3层协议的数据包。
    (2)    ptype_base管理正常的3层协议,仅接收具有正确协议标志符的数据包,例如,Internet的0x0800。

    注意sb_buff与net_device中几个字段的区别:
    sb_buff:
    unsigned short        protocol
    高层协议从二层设备的角度所看到的协议,典型的协议包括 IP,IPV6和 ARP,完整的列表在 include/linux/if_ether.h。 
    unsigned char pkt_type
    帧的类型,可能的取值都在include/linux/if_packet.h 中定义.
          
    net_device:
    unsigned short type 
        设备类型(以太网,帧中继等)。在include/linux/if_arp.h 中有完整的类型列表。

    2.2、协议处理函数注册
    当协议注册时,内核会调用dev_add_pack添加一个与之对应的packet_type数据结构:

    复制代码
    //include/linux/netdevice.h
    struct packet_type {
        unsigned short        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 *);
        void            *af_packet_priv;
        struct list_head    list;
    };
    复制代码

    type:协议类型,它可以取以下一些值。来看看if_ether.h中定义的协议的类型:

    Code

    dev:网络设备。PF_PACKET套接字通常使用它在特定的设备监听,例如,tcpdump -i eth0  通过PF_PACKET套接字创建一个packet_type实例,然后将dev指向eth0对应的net_device数据结构。
    func:协议处理函数。
    af_packet_priv:被PF_PACKET套接字使用。
    当同一个类型的协议有多个packet_type实例时,输入的帧会被所有的协议处理函数处理。

    IP协议的packet_type:

    复制代码
    //net/ipv4/ip_output.c
    static struct packet_type ip_packet_type = {
        .type = __constant_htons(ETH_P_IP),
        .func = ip_rcv,
    };

    //在inet_init中被调用
    void __init ip_init(void)
    {
        dev_add_pack(&ip_packet_type);

        ip_rt_init();
        inet_initpeers();

    #if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)
        igmp_mc_proc_init();
    #endif
    }
    //net/core/dev.c
    void dev_add_pack(struct packet_type *pt)
    {
        int hash;

        spin_lock_bh(&ptype_lock);
        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);
    }
    复制代码


    2.3、以太网帧(Ethernet)与802.3帧
    老的以太网的帧的格式与标准和802.3标准的格式分别如下:


    以太网的帧头(Ethernet frame header)的定义:

    //include/linux/if_ether.h
    struct ethhdr {
        unsigned char    h_dest[ETH_ALEN];    /* destination eth addr    */
        unsigned char    h_source[ETH_ALEN];    /* source ether addr    */
        unsigned short    h_proto;        /* packet type ID field    */
    } __attribute__((packed));


    h_proto>1536的以太网类型:


    2.4、eth_type_trans函数

    复制代码
    //net/ethernet/eth.c
    unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev)
    {
        struct ethhdr *eth;
        unsigned char *rawp;
        
        skb->mac.raw=skb->data;
        skb_pull(skb,ETH_HLEN);
        
        //取出以太网头
        eth = eth_hdr(skb);
        skb->input_dev = dev;
        
        //设置帧的类型
        if(*eth->h_dest&1) //广播和多播地址
        {
            if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
                skb->pkt_type=PACKET_BROADCAST;
            else
                skb->pkt_type=PACKET_MULTICAST;
        }
        
        /*
         *    This ALLMULTI check should be redundant by 1.4
         *    so don't forget to remove it.
         *
         *    Seems, you forgot to remove it. All silly devices
         *    seems to set IFF_PROMISC.
         */
         
        else if(1 /*dev->flags&IFF_PROMISC*/)
        {
            if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
                //如果帧的目标地址与网络设备的mac地址不同
                skb->pkt_type=PACKET_OTHERHOST;
        }
        
        if (ntohs(eth->h_proto) >= 1536)
            return eth->h_proto;
            
        rawp = skb->data;
        
        /*
         *    This is a magic hack to spot IPX packets. Older Novell breaks
         *    the protocol design and runs IPX over 802.3 without an 802.2 LLC
         *    layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
         *    won't work for fault tolerant netware but does for the rest.
         */
         //IPX数据包没有802.2标准的LLC层,0xFFFF为其标志位
        if (*(unsigned short *)rawp == 0xFFFF)
            return htons(ETH_P_802_3);
            
        /*
         *    Real 802.2 LLC
         */
         //802.2标准的LLC协议
        return htons(ETH_P_802_2);
    }
    复制代码

    该函数主要设置数据帧的类型,返回协议的类型。

  • 相关阅读:
    Python包中__init__.py作用
    获取web页面xpath
    Selenium学习(Python)
    C++构造函数的选择
    分布式实时处理系统——C++高性能编程
    构建之法(邹欣)
    分布式实时处理系统——通信基础
    go语言-csp模型-并发通道
    redis.conf 配置说明
    Linux fork()一个进程内核态的变化
  • 原文地址:https://www.cnblogs.com/xumaojun/p/8533216.html
Copyright © 2011-2022 走看看