xref: /linux-6.15/include/linux/etherdevice.h (revision 73eaef87)
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__
32f629d208SJoe Perches __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
333b04dddeSStephen Hemminger extern const struct header_ops eth_header_ops;
343b04dddeSStephen Hemminger 
35f629d208SJoe Perches int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
363b04dddeSStephen Hemminger 	       const void *daddr, const void *saddr, unsigned len);
37f629d208SJoe Perches int eth_rebuild_header(struct sk_buff *skb);
38f629d208SJoe Perches int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
39f629d208SJoe Perches int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
40f629d208SJoe Perches 		     __be16 type);
41f629d208SJoe Perches void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,
423b04dddeSStephen Hemminger 			     const unsigned char *haddr);
43f629d208SJoe Perches int eth_prepare_mac_addr_change(struct net_device *dev, void *p);
44f629d208SJoe Perches void eth_commit_mac_addr_change(struct net_device *dev, void *p);
45f629d208SJoe Perches int eth_mac_addr(struct net_device *dev, void *p);
46f629d208SJoe Perches int eth_change_mtu(struct net_device *dev, int new_mtu);
47f629d208SJoe Perches int eth_validate_addr(struct net_device *dev);
48ccad637bSStephen Hemminger 
49f629d208SJoe Perches struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
5036909ea4STom Herbert 					    unsigned int rxqs);
51f25f4e44SPeter P Waskiewicz Jr #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
5236909ea4STom Herbert #define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)
531da177e4SLinus Torvalds 
54b3343a2aSJohn Fastabend /* Reserved Ethernet Addresses per IEEE 802.1Q */
552bc80059SBen Hutchings static const u8 eth_reserved_addr_base[ETH_ALEN] __aligned(2) =
562bc80059SBen Hutchings { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
57b3343a2aSJohn Fastabend 
58b3343a2aSJohn Fastabend /**
5946acc460SBen Hutchings  * is_link_local_ether_addr - Determine if given Ethernet address is link-local
60b3343a2aSJohn Fastabend  * @addr: Pointer to a six-byte array containing the Ethernet address
61b3343a2aSJohn Fastabend  *
62b3343a2aSJohn Fastabend  * Return true if address is link local reserved addr (01:80:c2:00:00:0X) per
63b3343a2aSJohn Fastabend  * IEEE 802.1Q 8.6.3 Frame filtering.
64b3343a2aSJohn Fastabend  */
6546acc460SBen Hutchings static inline bool is_link_local_ether_addr(const u8 *addr)
66b3343a2aSJohn Fastabend {
6746acc460SBen Hutchings 	__be16 *a = (__be16 *)addr;
682bc80059SBen Hutchings 	static const __be16 *b = (const __be16 *)eth_reserved_addr_base;
69b3343a2aSJohn Fastabend 	static const __be16 m = cpu_to_be16(0xfff0);
70b3343a2aSJohn Fastabend 
71b3343a2aSJohn Fastabend 	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0;
72b3343a2aSJohn Fastabend }
73b3343a2aSJohn Fastabend 
741da177e4SLinus Torvalds /**
75c2da8acaSStephen Hemminger  * is_zero_ether_addr - Determine if give Ethernet address is all zeros.
76c2da8acaSStephen Hemminger  * @addr: Pointer to a six-byte array containing the Ethernet address
77c2da8acaSStephen Hemminger  *
78c2da8acaSStephen Hemminger  * Return true if the address is all zeroes.
791da177e4SLinus Torvalds  */
80b44907e6SJoe Perches static inline bool is_zero_ether_addr(const u8 *addr)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds 	return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds /**
86c2da8acaSStephen Hemminger  * is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
8779165121SMichael Ellerman  * @addr: Pointer to a six-byte array containing the Ethernet address
8879165121SMichael Ellerman  *
8979165121SMichael Ellerman  * Return true if the address is a multicast address.
9088df8ef5SStephen Hemminger  * By definition the broadcast address is also a multicast address.
9179165121SMichael Ellerman  */
92b44907e6SJoe Perches static inline bool is_multicast_ether_addr(const u8 *addr)
9379165121SMichael Ellerman {
94a02cec21SEric Dumazet 	return 0x01 & addr[0];
9579165121SMichael Ellerman }
9679165121SMichael Ellerman 
97c2da8acaSStephen Hemminger /**
98bc2cda1eSRandy Dunlap  * is_local_ether_addr - Determine if the Ethernet address is locally-assigned one (IEEE 802).
99e024715fSPaolo 'Blaisorblade' Giarrusso  * @addr: Pointer to a six-byte array containing the Ethernet address
100e024715fSPaolo 'Blaisorblade' Giarrusso  *
101e024715fSPaolo 'Blaisorblade' Giarrusso  * Return true if the address is a local address.
102e024715fSPaolo 'Blaisorblade' Giarrusso  */
103b44907e6SJoe Perches static inline bool is_local_ether_addr(const u8 *addr)
104e024715fSPaolo 'Blaisorblade' Giarrusso {
105a02cec21SEric Dumazet 	return 0x02 & addr[0];
106e024715fSPaolo 'Blaisorblade' Giarrusso }
107e024715fSPaolo 'Blaisorblade' Giarrusso 
108e024715fSPaolo 'Blaisorblade' Giarrusso /**
109c2da8acaSStephen Hemminger  * is_broadcast_ether_addr - Determine if the Ethernet address is broadcast
110c2da8acaSStephen Hemminger  * @addr: Pointer to a six-byte array containing the Ethernet address
111c2da8acaSStephen Hemminger  *
112c2da8acaSStephen Hemminger  * Return true if the address is the broadcast address.
113c2da8acaSStephen Hemminger  */
114b44907e6SJoe Perches static inline bool is_broadcast_ether_addr(const u8 *addr)
1159bd481f8SJeff Garzik {
1162407534fSStephen Hemminger 	return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
1179bd481f8SJeff Garzik }
1189bd481f8SJeff Garzik 
11979165121SMichael Ellerman /**
12051e7eed7STobias Klauser  * is_unicast_ether_addr - Determine if the Ethernet address is unicast
12151e7eed7STobias Klauser  * @addr: Pointer to a six-byte array containing the Ethernet address
12251e7eed7STobias Klauser  *
12351e7eed7STobias Klauser  * Return true if the address is a unicast address.
12451e7eed7STobias Klauser  */
125b44907e6SJoe Perches static inline bool is_unicast_ether_addr(const u8 *addr)
12651e7eed7STobias Klauser {
12751e7eed7STobias Klauser 	return !is_multicast_ether_addr(addr);
12851e7eed7STobias Klauser }
12951e7eed7STobias Klauser 
13051e7eed7STobias Klauser /**
1311da177e4SLinus Torvalds  * is_valid_ether_addr - Determine if the given Ethernet address is valid
1321da177e4SLinus Torvalds  * @addr: Pointer to a six-byte array containing the Ethernet address
1331da177e4SLinus Torvalds  *
1341da177e4SLinus Torvalds  * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
13579165121SMichael Ellerman  * a multicast address, and is not FF:FF:FF:FF:FF:FF.
1361da177e4SLinus Torvalds  *
1371da177e4SLinus Torvalds  * Return true if the address is valid.
1381da177e4SLinus Torvalds  */
139b44907e6SJoe Perches static inline bool is_valid_ether_addr(const u8 *addr)
1401da177e4SLinus Torvalds {
14179165121SMichael Ellerman 	/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
14279165121SMichael Ellerman 	 * explicitly check for it here. */
14379165121SMichael Ellerman 	return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /**
1470a4dd594SJoe Perches  * eth_random_addr - Generate software assigned random Ethernet address
1481da177e4SLinus Torvalds  * @addr: Pointer to a six-byte array containing the Ethernet address
1491da177e4SLinus Torvalds  *
1501da177e4SLinus Torvalds  * Generate a random Ethernet address (MAC) that is not multicast
1511da177e4SLinus Torvalds  * and has the local assigned bit set.
1521da177e4SLinus Torvalds  */
1530a4dd594SJoe Perches static inline void eth_random_addr(u8 *addr)
1541da177e4SLinus Torvalds {
1551da177e4SLinus Torvalds 	get_random_bytes(addr, ETH_ALEN);
1561da177e4SLinus Torvalds 	addr[0] &= 0xfe;	/* clear multicast bit */
1571da177e4SLinus Torvalds 	addr[0] |= 0x02;	/* set local assignment bit (IEEE802) */
1581da177e4SLinus Torvalds }
159360ac8e2SStephen Hemminger 
1600a4dd594SJoe Perches #define random_ether_addr(addr) eth_random_addr(addr)
1610a4dd594SJoe Perches 
162360ac8e2SStephen Hemminger /**
163ad7eee98SJohannes Berg  * eth_broadcast_addr - Assign broadcast address
164ad7eee98SJohannes Berg  * @addr: Pointer to a six-byte array containing the Ethernet address
165ad7eee98SJohannes Berg  *
166ad7eee98SJohannes Berg  * Assign the broadcast address to the given address array.
167ad7eee98SJohannes Berg  */
168ad7eee98SJohannes Berg static inline void eth_broadcast_addr(u8 *addr)
169ad7eee98SJohannes Berg {
170ad7eee98SJohannes Berg 	memset(addr, 0xff, ETH_ALEN);
171ad7eee98SJohannes Berg }
172ad7eee98SJohannes Berg 
173ad7eee98SJohannes Berg /**
1746d57e907SDuan Jiong  * eth_zero_addr - Assign zero address
1756d57e907SDuan Jiong  * @addr: Pointer to a six-byte array containing the Ethernet address
1766d57e907SDuan Jiong  *
1776d57e907SDuan Jiong  * Assign the zero address to the given address array.
1786d57e907SDuan Jiong  */
1796d57e907SDuan Jiong static inline void eth_zero_addr(u8 *addr)
1806d57e907SDuan Jiong {
1816d57e907SDuan Jiong 	memset(addr, 0x00, ETH_ALEN);
1826d57e907SDuan Jiong }
1836d57e907SDuan Jiong 
1846d57e907SDuan Jiong /**
1851a0d6ae5SDanny Kukawka  * eth_hw_addr_random - Generate software assigned random Ethernet and
1861a0d6ae5SDanny Kukawka  * set device flag
187c1f79426SStefan Assmann  * @dev: pointer to net_device structure
188c1f79426SStefan Assmann  *
1891a0d6ae5SDanny Kukawka  * Generate a random Ethernet address (MAC) to be used by a net device
1901a0d6ae5SDanny Kukawka  * and set addr_assign_type so the state can be read by sysfs and be
1911a0d6ae5SDanny Kukawka  * used by userspace.
192c1f79426SStefan Assmann  */
1931a0d6ae5SDanny Kukawka static inline void eth_hw_addr_random(struct net_device *dev)
194c1f79426SStefan Assmann {
195e41b2d7fSJiri Pirko 	dev->addr_assign_type = NET_ADDR_RANDOM;
1960a4dd594SJoe Perches 	eth_random_addr(dev->dev_addr);
197c1f79426SStefan Assmann }
198c1f79426SStefan Assmann 
199c1f79426SStefan Assmann /**
20083a093b4SBjørn Mork  * eth_hw_addr_inherit - Copy dev_addr from another net_device
20183a093b4SBjørn Mork  * @dst: pointer to net_device to copy dev_addr to
20283a093b4SBjørn Mork  * @src: pointer to net_device to copy dev_addr from
20383a093b4SBjørn Mork  *
20483a093b4SBjørn Mork  * Copy the Ethernet address from one net_device to another along with
20583a093b4SBjørn Mork  * the address attributes (addr_assign_type).
20683a093b4SBjørn Mork  */
20783a093b4SBjørn Mork static inline void eth_hw_addr_inherit(struct net_device *dst,
20883a093b4SBjørn Mork 				       struct net_device *src)
20983a093b4SBjørn Mork {
21083a093b4SBjørn Mork 	dst->addr_assign_type = src->addr_assign_type;
21183a093b4SBjørn Mork 	memcpy(dst->dev_addr, src->dev_addr, ETH_ALEN);
21283a093b4SBjørn Mork }
21383a093b4SBjørn Mork 
21483a093b4SBjørn Mork /**
215a599b0f5SJoe Perches  * ether_addr_equal - Compare two Ethernet addresses
216a599b0f5SJoe Perches  * @addr1: Pointer to a six-byte array containing the Ethernet address
217a599b0f5SJoe Perches  * @addr2: Pointer other six-byte array containing the Ethernet address
218a599b0f5SJoe Perches  *
219048b899cSstephen hemminger  * Compare two Ethernet addresses, returns true if equal
2200d74c42fSJoe Perches  *
2210d74c42fSJoe Perches  * Please note: addr1 & addr2 must both be aligned to u16.
222a599b0f5SJoe Perches  */
223a599b0f5SJoe Perches static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
224a599b0f5SJoe Perches {
2250d74c42fSJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
2260d74c42fSJoe Perches 	u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) |
2270d74c42fSJoe Perches 		   ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4)));
228a599b0f5SJoe Perches 
2290d74c42fSJoe Perches 	return fold == 0;
2301f87e235SEric Dumazet #else
2310d74c42fSJoe Perches 	const u16 *a = (const u16 *)addr1;
2320d74c42fSJoe Perches 	const u16 *b = (const u16 *)addr2;
2330d74c42fSJoe Perches 
2340d74c42fSJoe Perches 	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0;
2351f87e235SEric Dumazet #endif
2361f87e235SEric Dumazet }
2371f87e235SEric Dumazet 
2381f87e235SEric Dumazet /**
239baf523c9SJoe Perches  * ether_addr_equal_64bits - Compare two Ethernet addresses
240baf523c9SJoe Perches  * @addr1: Pointer to an array of 8 bytes
241baf523c9SJoe Perches  * @addr2: Pointer to an other array of 8 bytes
242baf523c9SJoe Perches  *
243048b899cSstephen hemminger  * Compare two Ethernet addresses, returns true if equal, false otherwise.
244baf523c9SJoe Perches  *
245baf523c9SJoe Perches  * The function doesn't need any conditional branches and possibly uses
246baf523c9SJoe Perches  * word memory accesses on CPU allowing cheap unaligned memory reads.
247048b899cSstephen hemminger  * arrays = { byte1, byte2, byte3, byte4, byte5, byte6, pad1, pad2 }
248baf523c9SJoe Perches  *
249048b899cSstephen hemminger  * Please note that alignment of addr1 & addr2 are only guaranteed to be 16 bits.
250baf523c9SJoe Perches  */
251baf523c9SJoe Perches 
252baf523c9SJoe Perches static inline bool ether_addr_equal_64bits(const u8 addr1[6+2],
253baf523c9SJoe Perches 					   const u8 addr2[6+2])
254baf523c9SJoe Perches {
2550d74c42fSJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
2560d74c42fSJoe Perches 	u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2);
257e550ba1aSJoe Perches 
2580d74c42fSJoe Perches #ifdef __BIG_ENDIAN
2590d74c42fSJoe Perches 	return (fold >> 16) == 0;
2600d74c42fSJoe Perches #else
2610d74c42fSJoe Perches 	return (fold << 16) == 0;
2620d74c42fSJoe Perches #endif
263e550ba1aSJoe Perches #else
264e550ba1aSJoe Perches 	return ether_addr_equal(addr1, addr2);
265e550ba1aSJoe Perches #endif
266baf523c9SJoe Perches }
267baf523c9SJoe Perches 
268baf523c9SJoe Perches /**
269*73eaef87SJoe Perches  * ether_addr_equal_unaligned - Compare two not u16 aligned Ethernet addresses
270*73eaef87SJoe Perches  * @addr1: Pointer to a six-byte array containing the Ethernet address
271*73eaef87SJoe Perches  * @addr2: Pointer other six-byte array containing the Ethernet address
272*73eaef87SJoe Perches  *
273*73eaef87SJoe Perches  * Compare two Ethernet addresses, returns true if equal
274*73eaef87SJoe Perches  *
275*73eaef87SJoe Perches  * Please note: Use only when any Ethernet address may not be u16 aligned.
276*73eaef87SJoe Perches  */
277*73eaef87SJoe Perches static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2)
278*73eaef87SJoe Perches {
279*73eaef87SJoe Perches #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
280*73eaef87SJoe Perches 	return ether_addr_equal(addr1, addr2);
281*73eaef87SJoe Perches #else
282*73eaef87SJoe Perches 	return memcmp(addr1, addr2, ETH_ALEN) == 0;
283*73eaef87SJoe Perches #endif
284*73eaef87SJoe Perches }
285*73eaef87SJoe Perches 
286*73eaef87SJoe Perches /**
287f001fde5SJiri Pirko  * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
288f001fde5SJiri Pirko  * @dev: Pointer to a device structure
289f001fde5SJiri Pirko  * @addr: Pointer to a six-byte array containing the Ethernet address
290f001fde5SJiri Pirko  *
291f001fde5SJiri Pirko  * Compare passed address with all addresses of the device. Return true if the
292f001fde5SJiri Pirko  * address if one of the device addresses.
293f001fde5SJiri Pirko  *
294e550ba1aSJoe Perches  * Note that this function calls ether_addr_equal_64bits() so take care of
295f001fde5SJiri Pirko  * the right padding.
296f001fde5SJiri Pirko  */
297f001fde5SJiri Pirko static inline bool is_etherdev_addr(const struct net_device *dev,
298f001fde5SJiri Pirko 				    const u8 addr[6 + 2])
299f001fde5SJiri Pirko {
300f001fde5SJiri Pirko 	struct netdev_hw_addr *ha;
301e550ba1aSJoe Perches 	bool res = false;
302f001fde5SJiri Pirko 
303f001fde5SJiri Pirko 	rcu_read_lock();
304f001fde5SJiri Pirko 	for_each_dev_addr(dev, ha) {
305e550ba1aSJoe Perches 		res = ether_addr_equal_64bits(addr, ha->addr);
306e550ba1aSJoe Perches 		if (res)
307f001fde5SJiri Pirko 			break;
308f001fde5SJiri Pirko 	}
309f001fde5SJiri Pirko 	rcu_read_unlock();
310e550ba1aSJoe Perches 	return res;
311f001fde5SJiri Pirko }
31279165121SMichael Ellerman #endif	/* __KERNEL__ */
3131da177e4SLinus Torvalds 
314aa4b9f53SHerbert Xu /**
315aa4b9f53SHerbert Xu  * compare_ether_header - Compare two Ethernet headers
316aa4b9f53SHerbert Xu  * @a: Pointer to Ethernet header
317aa4b9f53SHerbert Xu  * @b: Pointer to Ethernet header
318aa4b9f53SHerbert Xu  *
319048b899cSstephen hemminger  * Compare two Ethernet headers, returns 0 if equal.
320aa4b9f53SHerbert Xu  * This assumes that the network header (i.e., IP header) is 4-byte
321aa4b9f53SHerbert Xu  * aligned OR the platform can handle unaligned access.  This is the
322aa4b9f53SHerbert Xu  * case for all packets coming into netif_receive_skb or similar
323aa4b9f53SHerbert Xu  * entry points.
324aa4b9f53SHerbert Xu  */
325aa4b9f53SHerbert Xu 
32640d0802bSEric Dumazet static inline unsigned long compare_ether_header(const void *a, const void *b)
327aa4b9f53SHerbert Xu {
32840d0802bSEric Dumazet #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
32940d0802bSEric Dumazet 	unsigned long fold;
33040d0802bSEric Dumazet 
33140d0802bSEric Dumazet 	/*
33240d0802bSEric Dumazet 	 * We want to compare 14 bytes:
33340d0802bSEric Dumazet 	 *  [a0 ... a13] ^ [b0 ... b13]
33440d0802bSEric Dumazet 	 * Use two long XOR, ORed together, with an overlap of two bytes.
33540d0802bSEric Dumazet 	 *  [a0  a1  a2  a3  a4  a5  a6  a7 ] ^ [b0  b1  b2  b3  b4  b5  b6  b7 ] |
33640d0802bSEric Dumazet 	 *  [a6  a7  a8  a9  a10 a11 a12 a13] ^ [b6  b7  b8  b9  b10 b11 b12 b13]
33740d0802bSEric Dumazet 	 * This means the [a6 a7] ^ [b6 b7] part is done two times.
33840d0802bSEric Dumazet 	*/
33940d0802bSEric Dumazet 	fold = *(unsigned long *)a ^ *(unsigned long *)b;
34040d0802bSEric Dumazet 	fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6);
34140d0802bSEric Dumazet 	return fold;
34240d0802bSEric Dumazet #else
343aa4b9f53SHerbert Xu 	u32 *a32 = (u32 *)((u8 *)a + 2);
344aa4b9f53SHerbert Xu 	u32 *b32 = (u32 *)((u8 *)b + 2);
345aa4b9f53SHerbert Xu 
346aa4b9f53SHerbert Xu 	return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) |
347aa4b9f53SHerbert Xu 	       (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]);
34840d0802bSEric Dumazet #endif
349aa4b9f53SHerbert Xu }
350aa4b9f53SHerbert Xu 
3511da177e4SLinus Torvalds #endif	/* _LINUX_ETHERDEVICE_H */
352