ipv6: 64bit version of ipv6_addr_v4mapped().
[cascardo/linux.git] / include / net / ipv6.h
index 5af66b2..77cef33 100644 (file)
@@ -475,14 +475,25 @@ static inline u32 ipv6_addr_hash(const struct in6_addr *a)
 
 static inline bool ipv6_addr_loopback(const struct in6_addr *a)
 {
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       const unsigned long *ul = (const unsigned long *)a;
+
+       return (ul[0] | (ul[1] ^ cpu_to_be64(1))) == 0UL;
+#else
        return (a->s6_addr32[0] | a->s6_addr32[1] |
                a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0;
+#endif
 }
 
 static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
 {
-       return (a->s6_addr32[0] | a->s6_addr32[1] |
-                (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
+       return (
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+               *(__be64 *)a |
+#else
+               (a->s6_addr32[0] | a->s6_addr32[1]) |
+#endif
+               (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL;
 }
 
 /*
@@ -507,7 +518,7 @@ static inline void ipv6_addr_set_v4mapped(const __be32 addr,
  * find the first different bit between two addresses
  * length of address must be a multiple of 32bits
  */
-static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen)
+static inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen)
 {
        const __be32 *a1 = token1, *a2 = token2;
        int i;
@@ -539,6 +550,33 @@ static inline int __ipv6_addr_diff(const void *token1, const void *token2, int a
        return addrlen << 5;
 }
 
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+static inline int __ipv6_addr_diff64(const void *token1, const void *token2, int addrlen)
+{
+       const __be64 *a1 = token1, *a2 = token2;
+       int i;
+
+       addrlen >>= 3;
+
+       for (i = 0; i < addrlen; i++) {
+               __be64 xb = a1[i] ^ a2[i];
+               if (xb)
+                       return i * 64 + 63 - __fls(be64_to_cpu(xb));
+       }
+
+       return addrlen << 6;
+}
+#endif
+
+static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       if (__builtin_constant_p(addrlen) && !(addrlen & 7))
+               return __ipv6_addr_diff64(token1, token2, addrlen);
+#endif
+       return __ipv6_addr_diff32(token1, token2, addrlen);
+}
+
 static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2)
 {
        return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
@@ -546,6 +584,20 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
 
 extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
 
+/*
+ *     Header manipulation
+ */
+static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass,
+                               __be32 flowlabel)
+{
+       *(__be32 *)hdr = ntohl(0x60000000 | (tclass << 20)) | flowlabel;
+}
+
+static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr)
+{
+       return *(__be32 *)hdr & IPV6_FLOWINFO_MASK;
+}
+
 /*
  *     Prototypes exported by ipv6
  */