11.4.3 从套接口读取链路帧的编程方法

11.4.3  从套接口读取链路帧的编程方法

以太网的数据结构如图11.10所示,总长度最大为1518字节,最小为64字节,其中目标地址的MAC6字节,源地址MAC6字节,协议类型为2字节,含有461500字节的数据,尾部为4个字节的CRC校验和。以太网的CRC校验和一般由硬件自动设置或者剥离,应用层不用考虑。

11-10  以太网帧示意图

在头文件<Linux/if_ether.h>中定义了如下的常量:

 

#define ETH_ALEN    6               /*以太网地址,即MAC地址,6字节*/

#define ETH_HLEN    14              /*以太网头部的总长度*/

#define ETH_ZLEN    60              /*不含CRC校验的数据最小长度*/

#define ETH_DATA_LEN    1500        /*帧内数据的最大长度*/

#define ETH_FRAME_LEN   1514        /*不含CRC校验和的最大以太网数据长度*/

 

以太网头部结构定义为如下的形式:

 

struct ethhdr {

    unsigned char   h_dest[ETH_ALEN];       /*目的以太网地址*/

    unsigned char   h_source[ETH_ALEN];     /*源以太网地址*/

    __be16      h_proto;                    /*包类型*/

};

 

套接字文件描述符建立后,就可以从此描述符中读取数据,数据的格式为上述的以太网数据,即以太网帧。套接口建立以后,就可以从中循环读取捕获的链路层以太帧。要建立一个以太网缓冲区可以建立一个大小为ETH_FRAME_LEN的缓冲区,并将以太网的头部指向此缓冲区,例如:

 

char ef[ETH_FRAME_LEN];             /*以太帧缓冲区*/

struct ethhdr*p_ethhdr;         /*以太网头部指针*/

int n;         

p_ethhdr = (struct ethhdr*)ef; /*使p_ethhdr指向以太网帧的帧头*/

                            /*读取以太网数据,n为返回的实际捕获的以太帧的帧长*/

n = read(fd, ef, ETH_FRAME_LEN);  

 

接收数据以后,缓冲区ef与以太网头部的对应关系如图11.11所示。

 

 

11.11  以太网帧缓冲区与以太网头部结构ethhdr的映射关系

因此要获得以太网帧的目的MAC地址、源MAC地址和协议的类型,可以通过p_ethhdr->h_destp_ethhdr->h_sourcep_ethhdr->h_proto获得。下面的代码将以太网的信息打印出来:

 

/*打印以太网帧中的MAC地址和协议类型*/

/*目的MAC地址*/

printf("dest MAC: ");

for(i=0; i< ETH_ALEN-1; i++){

    printf("%02x-", p_ethhdr->h_dest[i]);

}

printf("%02x/n ", p_ethhdr->h_dest[ETH_ALEN-1]);

/*MAC地址*/

printf("source MAC: ");

for(i=0; i< ETH_ALEN-1; i++){

    printf("%02x-", p_ethhdr->h_source[i]);

}

printf("%02x/n ", p_ethhdr->h_dest[ETH_ALEN-1]);

/*协议类型,0x0800IP协议, 0x0806ARP协议, 0x8035RARP协议*/

printf("protocol: 0x%04x", ntohs(p_ethhdr->h_proto));

你可能感兴趣的:(11.4.3 从套接口读取链路帧的编程方法)