分类: 嵌入式
2015-06-13 21:36:45
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地址为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()进行转换;
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地址; |