diff options
-rw-r--r-- | include/linux/etherdevice.h | 42 | ||||
-rw-r--r-- | net/ethernet/eth.c | 6 |
2 files changed, 45 insertions, 3 deletions
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 0e5e97060034..1cb0f0b90926 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/if_ether.h> | 27 | #include <linux/if_ether.h> |
28 | #include <linux/netdevice.h> | 28 | #include <linux/netdevice.h> |
29 | #include <linux/random.h> | 29 | #include <linux/random.h> |
30 | #include <asm/unaligned.h> | ||
30 | 31 | ||
31 | #ifdef __KERNEL__ | 32 | #ifdef __KERNEL__ |
32 | extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); | 33 | extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); |
@@ -140,6 +141,47 @@ static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) | |||
140 | BUILD_BUG_ON(ETH_ALEN != 6); | 141 | BUILD_BUG_ON(ETH_ALEN != 6); |
141 | return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; | 142 | return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; |
142 | } | 143 | } |
144 | |||
145 | static inline unsigned long zap_last_2bytes(unsigned long value) | ||
146 | { | ||
147 | #ifdef __BIG_ENDIAN | ||
148 | return value >> 16; | ||
149 | #else | ||
150 | return value << 16; | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * compare_ether_addr_64bits - Compare two Ethernet addresses | ||
156 | * @addr1: Pointer to an array of 8 bytes | ||
157 | * @addr2: Pointer to an other array of 8 bytes | ||
158 | * | ||
159 | * Compare two ethernet addresses, returns 0 if equal. | ||
160 | * Same result than "memcmp(addr1, addr2, ETH_ALEN)" but without conditional | ||
161 | * branches, and possibly long word memory accesses on CPU allowing cheap | ||
162 | * unaligned memory reads. | ||
163 | * arrays = { byte1, byte2, byte3, byte4, byte6, byte7, pad1, pad2} | ||
164 | * | ||
165 | * Please note that alignment of addr1 & addr2 is only guaranted to be 16 bits. | ||
166 | */ | ||
167 | |||
168 | static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2], | ||
169 | const u8 addr2[6+2]) | ||
170 | { | ||
171 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
172 | unsigned long fold = ((*(unsigned long *)addr1) ^ | ||
173 | (*(unsigned long *)addr2)); | ||
174 | |||
175 | if (sizeof(fold) == 8) | ||
176 | return zap_last_2bytes(fold) != 0; | ||
177 | |||
178 | fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ | ||
179 | (*(unsigned long *)(addr2 + 4))); | ||
180 | return fold != 0; | ||
181 | #else | ||
182 | return compare_ether_addr(addr1, addr2); | ||
183 | #endif | ||
184 | } | ||
143 | #endif /* __KERNEL__ */ | 185 | #endif /* __KERNEL__ */ |
144 | 186 | ||
145 | #endif /* _LINUX_ETHERDEVICE_H */ | 187 | #endif /* _LINUX_ETHERDEVICE_H */ |
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index a87a171d9914..280352aba403 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
@@ -165,8 +165,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) | |||
165 | skb_pull(skb, ETH_HLEN); | 165 | skb_pull(skb, ETH_HLEN); |
166 | eth = eth_hdr(skb); | 166 | eth = eth_hdr(skb); |
167 | 167 | ||
168 | if (is_multicast_ether_addr(eth->h_dest)) { | 168 | if (unlikely(is_multicast_ether_addr(eth->h_dest))) { |
169 | if (!compare_ether_addr(eth->h_dest, dev->broadcast)) | 169 | if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) |
170 | skb->pkt_type = PACKET_BROADCAST; | 170 | skb->pkt_type = PACKET_BROADCAST; |
171 | else | 171 | else |
172 | skb->pkt_type = PACKET_MULTICAST; | 172 | skb->pkt_type = PACKET_MULTICAST; |
@@ -181,7 +181,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) | |||
181 | */ | 181 | */ |
182 | 182 | ||
183 | else if (1 /*dev->flags&IFF_PROMISC */ ) { | 183 | else if (1 /*dev->flags&IFF_PROMISC */ ) { |
184 | if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) | 184 | if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr))) |
185 | skb->pkt_type = PACKET_OTHERHOST; | 185 | skb->pkt_type = PACKET_OTHERHOST; |
186 | } | 186 | } |
187 | 187 | ||