Linux网络协议栈(四) -- 链路层(2)

2、协议相关
2.1、第3层协议的管理
在Linux内核中,有两种不同目的的3层协议:
(1)    ptype_all管理的协议主要用于分析目的,它接收所有到达第3层协议的数据包。
(2)    ptype_base管理正常的3层协议,仅接收具有正确协议标志符的数据包,例如,Internet的0x0800。
Linux网络协议栈(四) -- 链路层(2)_第1张图片
注意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中定义的协议的类型:

#define ETH_P_LOOP    0x0060        /* Ethernet Loopback packet    */
#define ETH_P_PUP    0x0200        /* Xerox PUP packet        */
#define ETH_P_PUPAT    0x0201        /* Xerox PUP Addr Trans packet    */
#define ETH_P_IP    0x0800        /* Internet Protocol packet    */
#define ETH_P_X25    0x0805        /* CCITT X.25            */
#define ETH_P_ARP    0x0806        /* Address Resolution packet    */
#define    ETH_P_BPQ    0x08FF        /* G8BPQ AX.25 Ethernet Packet    [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_IEEEPUP    0x0a00        /* Xerox IEEE802.3 PUP packet */
#define ETH_P_IEEEPUPAT    0x0a01        /* Xerox IEEE802.3 PUP Addr Trans packet */
#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
#define ETH_P_LAT       0x6004          /* DEC LAT                      */
#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
#define ETH_P_CUST      0x6006          /* DEC Customer use             */
#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
#define ETH_P_RARP      0x8035        /* Reverse Addr Res packet    */
#define ETH_P_ATALK    0x809B        /* Appletalk DDP        */
#define ETH_P_AARP    0x80F3        /* Appletalk AARP        */
#define ETH_P_8021Q    0x8100          /* 802.1Q VLAN Extended Header  */
#define ETH_P_IPX    0x8137        /* IPX over DIX            */
#define ETH_P_IPV6    0x86DD        /* IPv6 over bluebook        */
#define ETH_P_WCCP    0x883E        /* Web-cache coordination protocol
                     
* defined in draft-wilson-wrec-wccp-v2-00.txt */
#define ETH_P_PPP_DISC    0x8863        /* PPPoE discovery messages     */
#define ETH_P_PPP_SES    0x8864        /* PPPoE session messages    */
#define ETH_P_MPLS_UC    0x8847        /* MPLS Unicast traffic        */
#define ETH_P_MPLS_MC    0x8848        /* MPLS Multicast traffic    */
#define ETH_P_ATMMPOA    0x884c        /* MultiProtocol Over ATM    */
#define ETH_P_ATMFATE    0x8884        /* Frame-based ATM Transport
                     
* over Ethernet
                     
*/
#define ETH_P_AOE    0x88A2        /* ATA over Ethernet        */

/*
 *    Non DIX types. Won't clash for 1500 types.
 
*/
 
#define ETH_P_802_3    0x0001        /* Dummy type for 802.3 frames  */
#define ETH_P_AX25    0x0002        /* Dummy protocol id for AX.25  */
#define ETH_P_ALL    0x0003        /* Every packet (be careful!!!) */
#define ETH_P_802_2    0x0004        /* 802.2 frames         */
#define ETH_P_SNAP    0x0005        /* Internal only        */
#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
#define ETH_P_LOCALTALK 0x0009        /* Localtalk pseudo type     */
#define ETH_P_PPPTALK    0x0010        /* Dummy type for Atalk over PPP*/
#define ETH_P_TR_802_2    0x0011        /* 802.2 frames         */
#define ETH_P_MOBITEX    0x0015        /* Mobitex ([email protected])    */
#define ETH_P_CONTROL    0x0016        /* Card specific control frames */
#define ETH_P_IRDA    0x0017        /* Linux-IrDA            */
#define ETH_P_ECONET    0x0018        /* Acorn Econet            */
#define ETH_P_HDLC    0x0019        /* HDLC frames            */
#define ETH_P_ARCNET    0x001A        /* 1A for ArcNet :-)            *
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标准的格式分别如下:
Linux网络协议栈(四) -- 链路层(2)_第2张图片

以太网的帧头(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的以太网类型:
Linux网络协议栈(四) -- 链路层(2)_第3张图片

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);
}
复制代码
该函数主要设置数据帧的类型,返回协议的类型。

你可能感兴趣的:(数据结构,linux,header,网络协议,internet,linux内核)