struct ethhdr结构体详解
??? 在linux系統(tǒng)中,使用struct ethhdr結(jié)構(gòu)體來表示以太網(wǎng)幀的頭部。這個(gè)struct ethhdr結(jié)構(gòu)體位于#include<linux/if_ether.h>之中。
#define?ETH_ALEN?6??//定義了以太網(wǎng)接口的MAC地址的長(zhǎng)度為6個(gè)字節(jié)#define?ETH_HLAN?14??//定義了以太網(wǎng)幀的頭長(zhǎng)度為14個(gè)字節(jié)#define?ETH_ZLEN?60??//定義了以太網(wǎng)幀的最小長(zhǎng)度為?ETH_ZLEN?+?ETH_FCS_LEN?=?64個(gè)字節(jié)#define?ETH_DATA_LEN?1500??//定義了以太網(wǎng)幀的最大負(fù)載為1500個(gè)字節(jié)#define?ETH_FRAME_LEN?1514??//定義了以太網(wǎng)正的最大長(zhǎng)度為ETH_DATA_LEN?+?ETH_FCS_LEN?=?1518個(gè)字節(jié)#define?ETH_FCS_LEN?4???//定義了以太網(wǎng)幀的CRC值占4個(gè)字節(jié)struct?ethhdr {unsigned?char?h_dest[ETH_ALEN];?//目的MAC地址unsigned?char?h_source[ETH_ALEN];?//源MAC地址__u16?h_proto?;?//網(wǎng)絡(luò)層所使用的協(xié)議類型 }__attribute__((packed))??//用于告訴編譯器不要對(duì)這個(gè)結(jié)構(gòu)體中的縫隙部分進(jìn)行填充操作;網(wǎng)絡(luò)層所使用的協(xié)議類型有(常見的類型):
#define? ETH_P_IP 0x0800 //IP協(xié)議
#define? ETH_P_ARP 0x0806? //地址解析協(xié)議(Address Resolution Protocol)
#define? ETH_P_RARP 0x8035? //返向地址解析協(xié)議(Reverse Address Resolution Protocol)
#define? ETH_P_IPV6 0x86DD? //IPV6協(xié)議
static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
{
???? return (struct ethhdr *)skb_mac_header(skb);
}
//MAC地址的輸出格式。 "%02x"所表示的意思是:以16進(jìn)制的形式輸出,每一個(gè)16進(jìn)制字符占一個(gè)字節(jié)
#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] //定義了一個(gè)MAC字符緩存
??? 1.創(chuàng)建一個(gè)以太網(wǎng)頭結(jié)構(gòu)體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 : 原網(wǎng)絡(luò)設(shè)備
???? type: 網(wǎng)絡(luò)層的協(xié)議類型
???? daddr:目的MAC地址
???? saddr:源MAC地址
???? len? :一般可為0
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()將本地類型轉(zhuǎn)換為網(wǎng)絡(luò)類型elseeth->proto?=?htons(len);//如果?saddr?=?NULL的話,以太網(wǎng)幀頭中的源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.判斷一個(gè)網(wǎng)絡(luò)設(shè)備正在接受的struct sk_buff中的網(wǎng)絡(luò)層所使用的協(xié)議類型:
????? __be16 eth_type_trans(struct sk_buff *skb,
???????????????????????????? struct net_device *dev);
???? EXPORT_SYMBOL(eth_type_trans);
???? skb : 為正在接收的數(shù)據(jù)包;
???? dev : 為正在使用的網(wǎng)絡(luò)設(shè)備;
???? 返回值:為網(wǎng)絡(luò)字節(jié)序列,所以要使用ntohs()進(jìn)行轉(zhuǎn)換;
__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.從一個(gè)數(shù)據(jù)包(struct sk_buff)中提取源MAC地址:
??? int eth_header_parse(struct sk_buff *skb, u8 *haddr)
??? EXPORT_SYMBOL(eth_header_parse);
??? skb : 接收到的數(shù)據(jù)包;
??? haddr : 用于存放從接收的數(shù)據(jù)包中提取的硬件地址;
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個(gè)字節(jié),并不是我們常見的MAC字符串地址,那么如果將6字節(jié)的MAC地址轉(zhuǎn)化為我們常見的MAC字符串地址,使用下面這個(gè)函數(shù):
??? char *print_mac(char *buffer, const unsigned char *addr);
??? EXPORT_SYMBOL(print_mac);
??? buffer : 為MAC字符串地址存放的地方;
??? addr?? : 為6字節(jié)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; }???
????? 5.重新設(shè)置一個(gè)網(wǎng)絡(luò)設(shè)備的MAC地址:
???? int eth_mac_addr(struct net_device *dev, void *p);
???? EXPORT_SYMBOL(eth_mac_addr);
???? dev : 為將要被設(shè)置的網(wǎng)絡(luò)設(shè)備;
???? p?? : 為socket address;
int?eth_mac_addr(struct?net_device?*dev,?void?*p) {struct?sockaddr?*addr?=?p;//用于判斷網(wǎng)絡(luò)設(shè)備是否正在運(yùn)行if(netif_running(dev))return?-EBUSY;if(?!is_valid_ether_addr(addr->sa_data)?)return?-ETHADDRNOTAVAIL;memcpy(dev->dev_addr,?addr->sa_data,?ETH_ALEN);return?0; }????
????? 6.對(duì)一個(gè)struct net_device以太網(wǎng)網(wǎng)絡(luò)設(shè)備進(jìn)行初始化:
????? void ether_setup(struct net_device *dev);
????? EXPORT_SYMBOL(ether_setup);
??? 7.分配一個(gè)以太網(wǎng)網(wǎng)絡(luò)設(shè)備,并對(duì)其進(jìn)行初始化:
????? struct net_device *alloc_etherdev_mq(int sizeof_priv,
?????????????????????? u32 queue_count)
????? EXPORT_SYMBOL(alloc_etherdev_mq);
struct?net_device?*alloc_etherdev_mq(int?sizeof_priv,?unsigned?int?queue_count) {//?ether_setup為對(duì)分配的struct?net_device進(jìn)行初始化的函數(shù);//這個(gè)ether_setup是內(nèi)核的導(dǎo)出函數(shù),可以直接使用;return?alloc_netdev_mq(sizeof_priv,?"eth%d",?ether_setup,?queue_count); }#define?alloc_etherdev(sizeof_priv)??alloc_etherdev_mq(sizeof_priv,?1)???? 下面的這些函數(shù)用于struct ethhdr中的MAC地址的判斷:
???
??? 1.int is_zero_ether_addr(const u8 *addr);
????????? 用于判斷一個(gè)MAC地址是否為零;
static?inline?int?is_zero_ether_addr(const?u8?*addr) {return?!(addr[0]?|?addr[1]?|?addr[2]?|?addr[3]?|?addr[4]?|?addr[5]); }???? 2.int is_multicast_ether_addr(const u8 *addr)
?????????? 用于判斷addr中的MAC地址是否是組播MAC地址;
static?inline?int?is_multicast_ether_addr(const?u8?*addr) {//組播MAC地址的判斷方法:如果一個(gè)MAC地址的最低一位是1的話,則這個(gè)MAC地址為組播MAC地址;return?(0x01?&?addr[0]);? }
????? 3.int is_broadcast_ether_addr(const u8 *addr)
??????????? 用于判斷addr中的MAC地址是否是廣播地址;
static?inline?int?is_broadcast_ether_addr(const?u8?*addr) {return?(?addr[0]?&?addr[1]?&?addr[2]?&?addr[3]?&?addr[4]?&?addr[5]?)?==?0xff; }????
????? 4. int is_valid_ether_addr(const u8* addr)
???????????? 用于判斷addr中的MAC地址是否是有效的MAC地址;
static?inline?int?is_valid_ether_addr(const?u8?*addr) {//既不是組播地址,也不為0的MAC地址為有效的MAC地址;return?!is_multicast_ether_addr(addr)?&&?!is_zero_ether_addr(addr); }????? 5. void random_ether_addr(u8 *addr)
???????????? 用于軟件隨機(jī)產(chǎn)生一個(gè)MAC地址,然后存放與addr之中;
static?inline?void?random_ether_addr(u8?*addr) {get_random_bytes(addr,?ETH_ALEN);addr[0]?&?=?0xfe;addr[0]?|=?0x02;?//?IEEE802本地MAC地址 }
????? 6.int is_local_ether_addr(const u8 *addr)
?????????? 用于判斷addr中MAC地址是否是IEEE802中的本地MAC地址。
static?inline?int?is_local_ether_addr(const?u8?*addr) {return?(0x02?&?addr[0]); }?? 關(guān)于IEEE802 MAC地址的須知:
IEEE802 LAN6字節(jié)MAC地址是目前廣泛使用的LAN物理地址。IEEE802規(guī)定LAN地址字段的第一個(gè)字節(jié)的最低位表示I/G(Individual /Group)比特,即單地址/組地址比特。當(dāng)它為“0”時(shí),表示它代表一個(gè)單播地址,而這個(gè)位是“1”時(shí),表示它代表一個(gè)組地址。
IEEE802規(guī)定LAN地址字段的第一個(gè)字節(jié)的最低第二位表示G/L(Globe/Local)比特,即全球/本地比特。當(dāng)這個(gè)比特為“0”時(shí),表 示全球管理,物理地址是由全球局域網(wǎng)地址的法定管理機(jī)構(gòu)統(tǒng)一管理,全球管理地址在全球范圍內(nèi)不會(huì)發(fā)生地址沖突。當(dāng)這個(gè)比特為“1”時(shí),就是本地管理,局域 網(wǎng)管理員可以任意分配局部管理的網(wǎng)絡(luò)上的地址,只要在自己網(wǎng)絡(luò)中地址唯一不產(chǎn)生沖突即可,對(duì)外則沒有意義,局部管理很少使用。
在6個(gè)字節(jié)的其他46個(gè)比特用來標(biāo)識(shí)一個(gè)特定的MAC地址,46位的地址空間可表示約70萬億個(gè)地址,可以保證全球地址的唯一性。??
?
???? 7.unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2)
?????????? 用于比較兩個(gè)MAC地址是否相等,相等返回0,不相等返回1;
static?inline?unsigned?compare_ether_addr(const?u8?*addr1,?const?u8?*addr2) {const?u16?*a?=?(const?u16*)addr1;const?u16?*b?=?(const?u16*)addr2;return?(?(a[0]?^?b[0])?|?(a[1]?^?b[1])?|?(a[2]?^?b[2])?)?!=?0; }???? 以上的所有的函數(shù)可以通過 #include<linux/etherdevice.h>頭文件,來直接使用。
轉(zhuǎn)載于:https://blog.51cto.com/weiguozhihui/1586856
總結(jié)
以上是生活随笔為你收集整理的struct ethhdr结构体详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2014-12-5
- 下一篇: Structs2 ModelDriven