struct ethdr结构体剖析

在linux系统中,使用struct ethhdr结构体表示以太网帧的头部。这个struct ethhdr结构体位于linx内核include\linux\if_ether.h中。

struct ethhdr结构体原型如下所示:

<span style="font-family:FangSong_GB2312;font-size:18px;">struct ethhdr
{
    unsigned char h_dest[ETH_ALEN]; //目的MAC地址
     
    unsigned char h_source[ETH_ALEN]; //源MAC地址
     
    __u16 h_proto ; //网络层所使用的协议类型
}__attribute__((packed))  //用于告诉编译器不要对这个结构体中的缝隙部分进行填充操作;</span>

strcut ethhdr常见的操作

1.创建一个以太网头结构体struct ethhdr: 

<span style="font-family:FangSong_GB2312;font-size:18px;"><span style="white-space:pre">	</span>int eth_header(struct sk_buff *skb, struct net_device *dev,
                       u16 type, void *daddr, void *saddr, unsigned len)
<span style="white-space:pre">	</span>EXPORT_SYMBOL(eth_header);</span>

     skb : 将要去修改的struct sk_buff;

     dev : 原网络设备

     type: 网络层的协议类型

     daddr:目的MAC地址

     saddr:源MAC地址

     len  :一般可为0

int eth_header(struct sk_buff *skb, struct net_device *dev, 
<span style="white-space:pre">	</span>       u16 type, void *daddr, void *saddr, int len)
{
    //将skb->data = skb->data + ETH_ALEN;
    struct ethhdr *eth = (struct ethhdr*)skb_push(skb, ETH_ALEN);
     
    if(type != ETH_P_802_3)
       eth->proto = htons(type); // htons()将本地类型转换为网络类型
     else
       eth->proto = htons(len);
     
    //如果 saddr = NULL的话,以太网帧头中的源MAC地址为dev的MAC地址   
    if(!saddr)
       saddr = dev->dev_addr;
    memcpy(eth->saddr, saddr, ETH_ALEN);
     
    if(daddr)
    {
       memcpy(eth->daddr, daddr, ETH_ALEN);
       return ETH_HLEN ; //返回值为14
    }
     
    return -ETH_HLEN;
}

   2.判断一个网络设备正在接受的struct sk_buff中的网络层所使用的协议类型:

      __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);

     EXPORT_SYMBOL(eth_type_trans);

     skb : 为正在接收的数据包;

     dev : 为正在使用的网络设备;

     返回值:为网络字节序列,所以要使用ntohs()进行转换;

__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
    struct ethhdr *eth;
     
    skb->dev = dev;
    eth = eth_hdr(skb);
     
    if(netdev_uses_dsa_tags(dev))
         return htons(ETH_P_DSA);
          
    if(netdev_uses_trailer_tags(dev))
         return htons(ETH_P_TRAILER);
          
    if( ntohs(eth->h_proto) >= 1536 )
         return eth->h_proto;   

3.从一个数据包(struct sk_buff)中提取源MAC地址:

    int eth_header_parse(struct sk_buff *skb, u8 *haddr)

    EXPORT_SYMBOL(eth_header_parse);

    skb : 接收到的数据包;

    haddr : 用于存放从接收的数据包中提取的硬件地址;

int eth_header_parse(struct sk_buff *skb, u8 *haddr)
{
   struct ethhdr *eth = eth_hdr(skb);
   memcpy(haddr, eth->h_source, ETH_ALEN); //可知haddr中存放的是源MAC地址;
   return ETH_ALEN;
}

4.在struct ethhdr中MAC地址为6个字节,并不是我们常见的MAC字符串地址,那么如果将6字节的MAC地址转化为我们常见的MAC字符串地址,使用下面这个函数:

    char *print_mac(char *buffer, const unsigned char *addr);
    EXPORT_SYMBOL(print_mac);

    buffer : 为MAC字符串地址存放的地方;

    addr   : 为6字节MAC地址;

char *print_mac(char *buffer, const unsigned char *addr)
{
   // MAC_BUF_SIZE = 18
   // ETH_ALEN = 6
   _format_mac_addr(buffer, MAC_BUF_SIZE, addr, ETH_ALEN);
    
   return buffer;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值