Chinaunix首页 | 论坛 | 博客
  • 博客访问: 299525
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 715
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-20 20:38
文章分类
文章存档

2016年(20)

2015年(56)

分类: 嵌入式

2015-06-13 21:36:45

TD P { margin-bottom: 0cm; }P { margin-bottom: 0.21cm; }CODE.cjk { font-family: "Droid Sans Fallback",monospace; }CODE.ctl { font-family: "Lohit Hindi",monospace; }

ethhdr结构体详解

linux系统中,使用struct ethhdr结构体来表示以太网帧的头部。这个struct ethhdr结构体位于#include之中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#define ETH_ALEN 6  //定义了以太网接口的MAC地址的长度为6个字节

 

#define ETH_HLAN 14  //定义了以太网帧的头长度为14个字节

 

#define ETH_ZLEN 60  //定义了以太网帧的最小长度为 ETH_ZLEN + ETH_FCS_LEN = 64个字节

 

#define ETH_DATA_LEN 1500  //定义了以太网帧的最大负载为1500个字节

 

#define ETH_FRAME_LEN 1514  //定义了以太网正的最大长度为ETH_DATA_LEN + ETH_FCS_LEN = 1518个字节

 

#define ETH_FCS_LEN 4   //定义了以太网帧的CRC值占4个字节

 

 

struct ethhdr

{

    unsigned char h_dest[ETH_ALEN]; //目的MAC地址

     

    unsigned char h_source[ETH_ALEN]; //MAC地址

     

    __u16 h_proto ; //网络层所使用的协议类型

}__attribute__((packed))  //用于告诉编译器不要对这个结构体中的缝隙部分进行填充操作;


网络层所使用的协议类型有(常见的类型)

#define  ETH_P_IP 0x0800 //IP协议

#define  ETH_P_ARP 0x0806  //地址解析协议(Address Resolution Protocol)

#define  ETH_P_RARP 0x8035  //返向地址解析协议(Reverse Address Resolution Protocol)

#define  ETH_P_IPV6 0x86DD  //IPV6协议


static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)

{

     return (struct ethhdr *)skb_mac_header(skb);

}


//MAC地址的输出格式。 "%02x"所表示的意思是:以16进制的形式输出,每一个16进制字符占一个字节

#define MAC_FMT  "%02x:%02x:%02x:%02x:%02x:%02x"

#define MAC_BUF_LEN 18 //定义了用于存放MAC字符的缓存的大小

#define DECLARE_MAC_BUF(var)  char var[MAC_BUF_LEN] //定义了一个MAC字符缓存


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

     int eth_header(struct sk_buff *skb, struct net_device *dev,

                 u16 type, void *daddr, void *saddr, unsigned len)

      EXPORT_SYMBOL(eth_header);

     skb : 将要去修改的struct sk_buff

     dev : 原网络设备

     type: 网络层的协议类型

     daddr:目的MAC地址

     saddr:MAC地址

     len  :一般可为0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

int eth_header(struct sk_buff *skb, struct net_device *dev, 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地址为devMAC地址   

    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()进行转换;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

__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 : 用于存放从接收的数据包中提取的硬件地址;

1

2

3

4

5

6

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地址;


阅读(4041) | 评论(0) | 转发(0) |
0

上一篇:Mount 命令

下一篇:字符设备驱动(新)

给主人留下些什么吧!~~