11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * INET An implementation of the TCP/IP protocol suite for the LINUX 31da177e4SLinus Torvalds * operating system. NET is implemented using the BSD Socket 41da177e4SLinus Torvalds * interface as the means of communication with the user level. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Definitions for the Ethernet handlers. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Version: @(#)eth.h 1.0.4 05/13/93 91da177e4SLinus Torvalds * 1002c30a84SJesper Juhl * Authors: Ross Biro 111da177e4SLinus Torvalds * Fred N. van Kempen, <[email protected]> 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * Relocated to include/linux where it belongs by Alan Cox 141da177e4SLinus Torvalds * <[email protected]> 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 171da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 181da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 191da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds #ifndef _LINUX_ETHERDEVICE_H 231da177e4SLinus Torvalds #define _LINUX_ETHERDEVICE_H 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <linux/if_ether.h> 26bcd61272SArnd Bergmann #include <linux/netdevice.h> 271da177e4SLinus Torvalds #include <linux/random.h> 281f87e235SEric Dumazet #include <asm/unaligned.h> 290d74c42fSJoe Perches #include <asm/bitsperlong.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #ifdef __KERNEL__ 32*56193d1bSAlexander Duyck u32 eth_get_headlen(void *data, unsigned int max_len); 33f629d208SJoe Perches __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); 343b04dddeSStephen Hemminger extern const struct header_ops eth_header_ops; 353b04dddeSStephen Hemminger 36f629d208SJoe Perches int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, 373b04dddeSStephen Hemminger const void *daddr, const void *saddr, unsigned len); 38f629d208SJoe Perches int eth_rebuild_header(struct sk_buff *skb); 39f629d208SJoe Perches int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); 40f629d208SJoe Perches int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, 41f629d208SJoe Perches __be16 type); 42f629d208SJoe Perches void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev, 433b04dddeSStephen Hemminger const unsigned char *haddr); 44f629d208SJoe Perches int eth_prepare_mac_addr_change(struct net_device *dev, void *p); 45f629d208SJoe Perches void eth_commit_mac_addr_change(struct net_device *dev, void *p); 46f629d208SJoe Perches int eth_mac_addr(struct net_device *dev, void *p); 47f629d208SJoe Perches int eth_change_mtu(struct net_device *dev, int new_mtu); 48f629d208SJoe Perches int eth_validate_addr(struct net_device *dev); 49ccad637bSStephen Hemminger 50f629d208SJoe Perches struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, 5136909ea4STom Herbert unsigned int rxqs); 52f25f4e44SPeter P Waskiewicz Jr #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1) 5336909ea4STom Herbert #define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count) 541da177e4SLinus Torvalds 55b3343a2aSJohn Fastabend /* Reserved Ethernet Addresses per IEEE 802.1Q */ 562bc80059SBen Hutchings static const u8 eth_reserved_addr_base[ETH_ALEN] __aligned(2) = 572bc80059SBen Hutchings { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; 58b3343a2aSJohn Fastabend 59b3343a2aSJohn Fastabend /** 6046acc460SBen Hutchings * is_link_local_ether_addr - Determine if given Ethernet address is link-local 61b3343a2aSJohn Fastabend * @addr: Pointer to a six-byte array containing the Ethernet address 62b3343a2aSJohn Fastabend * 63b3343a2aSJohn Fastabend * Return true if address is link local reserved addr (01:80:c2:00:00:0X) per 64b3343a2aSJohn Fastabend * IEEE 802.1Q 8.6.3 Frame filtering. 652c722fe1SJoe Perches * 662c722fe1SJoe Perches * Please note: addr must be aligned to u16. 67b3343a2aSJohn Fastabend */ 6846acc460SBen Hutchings static inline bool is_link_local_ether_addr(const u8 *addr) 69b3343a2aSJohn Fastabend { 7046acc460SBen Hutchings __be16 *a = (__be16 *)addr; 712bc80059SBen Hutchings static const __be16 *b = (const __be16 *)eth_reserved_addr_base; 72b3343a2aSJohn Fastabend static const __be16 m = cpu_to_be16(0xfff0); 73b3343a2aSJohn Fastabend 742c722fe1SJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 752c722fe1SJoe Perches return (((*(const u32 *)addr) ^ (*(const u32 *)b)) | 762c722fe1SJoe Perches ((a[2] ^ b[2]) & m)) == 0; 772c722fe1SJoe Perches #else 78b3343a2aSJohn Fastabend return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; 792c722fe1SJoe Perches #endif 80b3343a2aSJohn Fastabend } 81b3343a2aSJohn Fastabend 821da177e4SLinus Torvalds /** 83c2da8acaSStephen Hemminger * is_zero_ether_addr - Determine if give Ethernet address is all zeros. 84c2da8acaSStephen Hemminger * @addr: Pointer to a six-byte array containing the Ethernet address 85c2da8acaSStephen Hemminger * 86c2da8acaSStephen Hemminger * Return true if the address is all zeroes. 872c722fe1SJoe Perches * 882c722fe1SJoe Perches * Please note: addr must be aligned to u16. 891da177e4SLinus Torvalds */ 90b44907e6SJoe Perches static inline bool is_zero_ether_addr(const u8 *addr) 911da177e4SLinus Torvalds { 922c722fe1SJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 932c722fe1SJoe Perches return ((*(const u32 *)addr) | (*(const u16 *)(addr + 4))) == 0; 942c722fe1SJoe Perches #else 952c722fe1SJoe Perches return (*(const u16 *)(addr + 0) | 962c722fe1SJoe Perches *(const u16 *)(addr + 2) | 972c722fe1SJoe Perches *(const u16 *)(addr + 4)) == 0; 982c722fe1SJoe Perches #endif 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /** 102c2da8acaSStephen Hemminger * is_multicast_ether_addr - Determine if the Ethernet address is a multicast. 10379165121SMichael Ellerman * @addr: Pointer to a six-byte array containing the Ethernet address 10479165121SMichael Ellerman * 10579165121SMichael Ellerman * Return true if the address is a multicast address. 10688df8ef5SStephen Hemminger * By definition the broadcast address is also a multicast address. 10779165121SMichael Ellerman */ 108b44907e6SJoe Perches static inline bool is_multicast_ether_addr(const u8 *addr) 10979165121SMichael Ellerman { 110a02cec21SEric Dumazet return 0x01 & addr[0]; 11179165121SMichael Ellerman } 11279165121SMichael Ellerman 113c2da8acaSStephen Hemminger /** 114bc2cda1eSRandy Dunlap * is_local_ether_addr - Determine if the Ethernet address is locally-assigned one (IEEE 802). 115e024715fSPaolo 'Blaisorblade' Giarrusso * @addr: Pointer to a six-byte array containing the Ethernet address 116e024715fSPaolo 'Blaisorblade' Giarrusso * 117e024715fSPaolo 'Blaisorblade' Giarrusso * Return true if the address is a local address. 118e024715fSPaolo 'Blaisorblade' Giarrusso */ 119b44907e6SJoe Perches static inline bool is_local_ether_addr(const u8 *addr) 120e024715fSPaolo 'Blaisorblade' Giarrusso { 121a02cec21SEric Dumazet return 0x02 & addr[0]; 122e024715fSPaolo 'Blaisorblade' Giarrusso } 123e024715fSPaolo 'Blaisorblade' Giarrusso 124e024715fSPaolo 'Blaisorblade' Giarrusso /** 125c2da8acaSStephen Hemminger * is_broadcast_ether_addr - Determine if the Ethernet address is broadcast 126c2da8acaSStephen Hemminger * @addr: Pointer to a six-byte array containing the Ethernet address 127c2da8acaSStephen Hemminger * 128c2da8acaSStephen Hemminger * Return true if the address is the broadcast address. 1292c722fe1SJoe Perches * 1302c722fe1SJoe Perches * Please note: addr must be aligned to u16. 131c2da8acaSStephen Hemminger */ 132b44907e6SJoe Perches static inline bool is_broadcast_ether_addr(const u8 *addr) 1339bd481f8SJeff Garzik { 1342c722fe1SJoe Perches return (*(const u16 *)(addr + 0) & 1352c722fe1SJoe Perches *(const u16 *)(addr + 2) & 1362c722fe1SJoe Perches *(const u16 *)(addr + 4)) == 0xffff; 1379bd481f8SJeff Garzik } 1389bd481f8SJeff Garzik 13979165121SMichael Ellerman /** 14051e7eed7STobias Klauser * is_unicast_ether_addr - Determine if the Ethernet address is unicast 14151e7eed7STobias Klauser * @addr: Pointer to a six-byte array containing the Ethernet address 14251e7eed7STobias Klauser * 14351e7eed7STobias Klauser * Return true if the address is a unicast address. 14451e7eed7STobias Klauser */ 145b44907e6SJoe Perches static inline bool is_unicast_ether_addr(const u8 *addr) 14651e7eed7STobias Klauser { 14751e7eed7STobias Klauser return !is_multicast_ether_addr(addr); 14851e7eed7STobias Klauser } 14951e7eed7STobias Klauser 15051e7eed7STobias Klauser /** 1511da177e4SLinus Torvalds * is_valid_ether_addr - Determine if the given Ethernet address is valid 1521da177e4SLinus Torvalds * @addr: Pointer to a six-byte array containing the Ethernet address 1531da177e4SLinus Torvalds * 1541da177e4SLinus Torvalds * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not 15579165121SMichael Ellerman * a multicast address, and is not FF:FF:FF:FF:FF:FF. 1561da177e4SLinus Torvalds * 1571da177e4SLinus Torvalds * Return true if the address is valid. 1582c722fe1SJoe Perches * 1592c722fe1SJoe Perches * Please note: addr must be aligned to u16. 1601da177e4SLinus Torvalds */ 161b44907e6SJoe Perches static inline bool is_valid_ether_addr(const u8 *addr) 1621da177e4SLinus Torvalds { 16379165121SMichael Ellerman /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to 16479165121SMichael Ellerman * explicitly check for it here. */ 16579165121SMichael Ellerman return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds /** 1690a4dd594SJoe Perches * eth_random_addr - Generate software assigned random Ethernet address 1701da177e4SLinus Torvalds * @addr: Pointer to a six-byte array containing the Ethernet address 1711da177e4SLinus Torvalds * 1721da177e4SLinus Torvalds * Generate a random Ethernet address (MAC) that is not multicast 1731da177e4SLinus Torvalds * and has the local assigned bit set. 1741da177e4SLinus Torvalds */ 1750a4dd594SJoe Perches static inline void eth_random_addr(u8 *addr) 1761da177e4SLinus Torvalds { 1771da177e4SLinus Torvalds get_random_bytes(addr, ETH_ALEN); 1781da177e4SLinus Torvalds addr[0] &= 0xfe; /* clear multicast bit */ 1791da177e4SLinus Torvalds addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ 1801da177e4SLinus Torvalds } 181360ac8e2SStephen Hemminger 1820a4dd594SJoe Perches #define random_ether_addr(addr) eth_random_addr(addr) 1830a4dd594SJoe Perches 184360ac8e2SStephen Hemminger /** 185ad7eee98SJohannes Berg * eth_broadcast_addr - Assign broadcast address 186ad7eee98SJohannes Berg * @addr: Pointer to a six-byte array containing the Ethernet address 187ad7eee98SJohannes Berg * 188ad7eee98SJohannes Berg * Assign the broadcast address to the given address array. 189ad7eee98SJohannes Berg */ 190ad7eee98SJohannes Berg static inline void eth_broadcast_addr(u8 *addr) 191ad7eee98SJohannes Berg { 192ad7eee98SJohannes Berg memset(addr, 0xff, ETH_ALEN); 193ad7eee98SJohannes Berg } 194ad7eee98SJohannes Berg 195ad7eee98SJohannes Berg /** 1966d57e907SDuan Jiong * eth_zero_addr - Assign zero address 1976d57e907SDuan Jiong * @addr: Pointer to a six-byte array containing the Ethernet address 1986d57e907SDuan Jiong * 1996d57e907SDuan Jiong * Assign the zero address to the given address array. 2006d57e907SDuan Jiong */ 2016d57e907SDuan Jiong static inline void eth_zero_addr(u8 *addr) 2026d57e907SDuan Jiong { 2036d57e907SDuan Jiong memset(addr, 0x00, ETH_ALEN); 2046d57e907SDuan Jiong } 2056d57e907SDuan Jiong 2066d57e907SDuan Jiong /** 2071a0d6ae5SDanny Kukawka * eth_hw_addr_random - Generate software assigned random Ethernet and 2081a0d6ae5SDanny Kukawka * set device flag 209c1f79426SStefan Assmann * @dev: pointer to net_device structure 210c1f79426SStefan Assmann * 2111a0d6ae5SDanny Kukawka * Generate a random Ethernet address (MAC) to be used by a net device 2121a0d6ae5SDanny Kukawka * and set addr_assign_type so the state can be read by sysfs and be 2131a0d6ae5SDanny Kukawka * used by userspace. 214c1f79426SStefan Assmann */ 2151a0d6ae5SDanny Kukawka static inline void eth_hw_addr_random(struct net_device *dev) 216c1f79426SStefan Assmann { 217e41b2d7fSJiri Pirko dev->addr_assign_type = NET_ADDR_RANDOM; 2180a4dd594SJoe Perches eth_random_addr(dev->dev_addr); 219c1f79426SStefan Assmann } 220c1f79426SStefan Assmann 221c1f79426SStefan Assmann /** 222286ab723SJoe Perches * ether_addr_copy - Copy an Ethernet address 223286ab723SJoe Perches * @dst: Pointer to a six-byte array Ethernet address destination 224286ab723SJoe Perches * @src: Pointer to a six-byte array Ethernet address source 225286ab723SJoe Perches * 226286ab723SJoe Perches * Please note: dst & src must both be aligned to u16. 227286ab723SJoe Perches */ 228286ab723SJoe Perches static inline void ether_addr_copy(u8 *dst, const u8 *src) 229286ab723SJoe Perches { 230286ab723SJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 231286ab723SJoe Perches *(u32 *)dst = *(const u32 *)src; 232286ab723SJoe Perches *(u16 *)(dst + 4) = *(const u16 *)(src + 4); 233286ab723SJoe Perches #else 234286ab723SJoe Perches u16 *a = (u16 *)dst; 235286ab723SJoe Perches const u16 *b = (const u16 *)src; 236286ab723SJoe Perches 237286ab723SJoe Perches a[0] = b[0]; 238286ab723SJoe Perches a[1] = b[1]; 239286ab723SJoe Perches a[2] = b[2]; 240286ab723SJoe Perches #endif 241286ab723SJoe Perches } 242286ab723SJoe Perches 243286ab723SJoe Perches /** 24483a093b4SBjørn Mork * eth_hw_addr_inherit - Copy dev_addr from another net_device 24583a093b4SBjørn Mork * @dst: pointer to net_device to copy dev_addr to 24683a093b4SBjørn Mork * @src: pointer to net_device to copy dev_addr from 24783a093b4SBjørn Mork * 24883a093b4SBjørn Mork * Copy the Ethernet address from one net_device to another along with 24983a093b4SBjørn Mork * the address attributes (addr_assign_type). 25083a093b4SBjørn Mork */ 25183a093b4SBjørn Mork static inline void eth_hw_addr_inherit(struct net_device *dst, 25283a093b4SBjørn Mork struct net_device *src) 25383a093b4SBjørn Mork { 25483a093b4SBjørn Mork dst->addr_assign_type = src->addr_assign_type; 255286ab723SJoe Perches ether_addr_copy(dst->dev_addr, src->dev_addr); 25683a093b4SBjørn Mork } 25783a093b4SBjørn Mork 25883a093b4SBjørn Mork /** 259a599b0f5SJoe Perches * ether_addr_equal - Compare two Ethernet addresses 260a599b0f5SJoe Perches * @addr1: Pointer to a six-byte array containing the Ethernet address 261a599b0f5SJoe Perches * @addr2: Pointer other six-byte array containing the Ethernet address 262a599b0f5SJoe Perches * 263048b899cSstephen hemminger * Compare two Ethernet addresses, returns true if equal 2640d74c42fSJoe Perches * 2650d74c42fSJoe Perches * Please note: addr1 & addr2 must both be aligned to u16. 266a599b0f5SJoe Perches */ 267a599b0f5SJoe Perches static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) 268a599b0f5SJoe Perches { 2690d74c42fSJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 2700d74c42fSJoe Perches u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | 2710d74c42fSJoe Perches ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); 272a599b0f5SJoe Perches 2730d74c42fSJoe Perches return fold == 0; 2741f87e235SEric Dumazet #else 2750d74c42fSJoe Perches const u16 *a = (const u16 *)addr1; 2760d74c42fSJoe Perches const u16 *b = (const u16 *)addr2; 2770d74c42fSJoe Perches 2780d74c42fSJoe Perches return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; 2791f87e235SEric Dumazet #endif 2801f87e235SEric Dumazet } 2811f87e235SEric Dumazet 2821f87e235SEric Dumazet /** 283baf523c9SJoe Perches * ether_addr_equal_64bits - Compare two Ethernet addresses 284baf523c9SJoe Perches * @addr1: Pointer to an array of 8 bytes 285baf523c9SJoe Perches * @addr2: Pointer to an other array of 8 bytes 286baf523c9SJoe Perches * 287048b899cSstephen hemminger * Compare two Ethernet addresses, returns true if equal, false otherwise. 288baf523c9SJoe Perches * 289baf523c9SJoe Perches * The function doesn't need any conditional branches and possibly uses 290baf523c9SJoe Perches * word memory accesses on CPU allowing cheap unaligned memory reads. 291048b899cSstephen hemminger * arrays = { byte1, byte2, byte3, byte4, byte5, byte6, pad1, pad2 } 292baf523c9SJoe Perches * 293048b899cSstephen hemminger * Please note that alignment of addr1 & addr2 are only guaranteed to be 16 bits. 294baf523c9SJoe Perches */ 295baf523c9SJoe Perches 296baf523c9SJoe Perches static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], 297baf523c9SJoe Perches const u8 addr2[6+2]) 298baf523c9SJoe Perches { 2990d74c42fSJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 3000d74c42fSJoe Perches u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); 301e550ba1aSJoe Perches 3020d74c42fSJoe Perches #ifdef __BIG_ENDIAN 3030d74c42fSJoe Perches return (fold >> 16) == 0; 3040d74c42fSJoe Perches #else 3050d74c42fSJoe Perches return (fold << 16) == 0; 3060d74c42fSJoe Perches #endif 307e550ba1aSJoe Perches #else 308e550ba1aSJoe Perches return ether_addr_equal(addr1, addr2); 309e550ba1aSJoe Perches #endif 310baf523c9SJoe Perches } 311baf523c9SJoe Perches 312baf523c9SJoe Perches /** 31373eaef87SJoe Perches * ether_addr_equal_unaligned - Compare two not u16 aligned Ethernet addresses 31473eaef87SJoe Perches * @addr1: Pointer to a six-byte array containing the Ethernet address 31573eaef87SJoe Perches * @addr2: Pointer other six-byte array containing the Ethernet address 31673eaef87SJoe Perches * 31773eaef87SJoe Perches * Compare two Ethernet addresses, returns true if equal 31873eaef87SJoe Perches * 31973eaef87SJoe Perches * Please note: Use only when any Ethernet address may not be u16 aligned. 32073eaef87SJoe Perches */ 32173eaef87SJoe Perches static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) 32273eaef87SJoe Perches { 32373eaef87SJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 32473eaef87SJoe Perches return ether_addr_equal(addr1, addr2); 32573eaef87SJoe Perches #else 32673eaef87SJoe Perches return memcmp(addr1, addr2, ETH_ALEN) == 0; 32773eaef87SJoe Perches #endif 32873eaef87SJoe Perches } 32973eaef87SJoe Perches 33073eaef87SJoe Perches /** 331f001fde5SJiri Pirko * is_etherdev_addr - Tell if given Ethernet address belongs to the device. 332f001fde5SJiri Pirko * @dev: Pointer to a device structure 333f001fde5SJiri Pirko * @addr: Pointer to a six-byte array containing the Ethernet address 334f001fde5SJiri Pirko * 335f001fde5SJiri Pirko * Compare passed address with all addresses of the device. Return true if the 336f001fde5SJiri Pirko * address if one of the device addresses. 337f001fde5SJiri Pirko * 338e550ba1aSJoe Perches * Note that this function calls ether_addr_equal_64bits() so take care of 339f001fde5SJiri Pirko * the right padding. 340f001fde5SJiri Pirko */ 341f001fde5SJiri Pirko static inline bool is_etherdev_addr(const struct net_device *dev, 342f001fde5SJiri Pirko const u8 addr[6 + 2]) 343f001fde5SJiri Pirko { 344f001fde5SJiri Pirko struct netdev_hw_addr *ha; 345e550ba1aSJoe Perches bool res = false; 346f001fde5SJiri Pirko 347f001fde5SJiri Pirko rcu_read_lock(); 348f001fde5SJiri Pirko for_each_dev_addr(dev, ha) { 349e550ba1aSJoe Perches res = ether_addr_equal_64bits(addr, ha->addr); 350e550ba1aSJoe Perches if (res) 351f001fde5SJiri Pirko break; 352f001fde5SJiri Pirko } 353f001fde5SJiri Pirko rcu_read_unlock(); 354e550ba1aSJoe Perches return res; 355f001fde5SJiri Pirko } 35679165121SMichael Ellerman #endif /* __KERNEL__ */ 3571da177e4SLinus Torvalds 358aa4b9f53SHerbert Xu /** 359aa4b9f53SHerbert Xu * compare_ether_header - Compare two Ethernet headers 360aa4b9f53SHerbert Xu * @a: Pointer to Ethernet header 361aa4b9f53SHerbert Xu * @b: Pointer to Ethernet header 362aa4b9f53SHerbert Xu * 363048b899cSstephen hemminger * Compare two Ethernet headers, returns 0 if equal. 364aa4b9f53SHerbert Xu * This assumes that the network header (i.e., IP header) is 4-byte 365aa4b9f53SHerbert Xu * aligned OR the platform can handle unaligned access. This is the 366aa4b9f53SHerbert Xu * case for all packets coming into netif_receive_skb or similar 367aa4b9f53SHerbert Xu * entry points. 368aa4b9f53SHerbert Xu */ 369aa4b9f53SHerbert Xu 37040d0802bSEric Dumazet static inline unsigned long compare_ether_header(const void *a, const void *b) 371aa4b9f53SHerbert Xu { 37240d0802bSEric Dumazet #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 37340d0802bSEric Dumazet unsigned long fold; 37440d0802bSEric Dumazet 37540d0802bSEric Dumazet /* 37640d0802bSEric Dumazet * We want to compare 14 bytes: 37740d0802bSEric Dumazet * [a0 ... a13] ^ [b0 ... b13] 37840d0802bSEric Dumazet * Use two long XOR, ORed together, with an overlap of two bytes. 37940d0802bSEric Dumazet * [a0 a1 a2 a3 a4 a5 a6 a7 ] ^ [b0 b1 b2 b3 b4 b5 b6 b7 ] | 38040d0802bSEric Dumazet * [a6 a7 a8 a9 a10 a11 a12 a13] ^ [b6 b7 b8 b9 b10 b11 b12 b13] 38140d0802bSEric Dumazet * This means the [a6 a7] ^ [b6 b7] part is done two times. 38240d0802bSEric Dumazet */ 38340d0802bSEric Dumazet fold = *(unsigned long *)a ^ *(unsigned long *)b; 38440d0802bSEric Dumazet fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6); 38540d0802bSEric Dumazet return fold; 38640d0802bSEric Dumazet #else 387aa4b9f53SHerbert Xu u32 *a32 = (u32 *)((u8 *)a + 2); 388aa4b9f53SHerbert Xu u32 *b32 = (u32 *)((u8 *)b + 2); 389aa4b9f53SHerbert Xu 390aa4b9f53SHerbert Xu return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) | 391aa4b9f53SHerbert Xu (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]); 39240d0802bSEric Dumazet #endif 393aa4b9f53SHerbert Xu } 394aa4b9f53SHerbert Xu 3951da177e4SLinus Torvalds #endif /* _LINUX_ETHERDEVICE_H */ 396