[XFRM]: xrfm_replay_check() annotations
[linux-2.6-microblaze.git] / net / xfrm / xfrm_state.c
index 0bc6a4b..33e9829 100644 (file)
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
 #include <linux/module.h>
-#include <linux/bootmem.h>
-#include <linux/vmalloc.h>
 #include <linux/cache.h>
 #include <asm/uaccess.h>
 
+#include "xfrm_hash.h"
+
 struct sock *xfrm_nl;
 EXPORT_SYMBOL(xfrm_nl);
 
@@ -55,106 +55,24 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
 static unsigned int xfrm_state_num;
 static unsigned int xfrm_state_genid;
 
-static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
-{
-       return ntohl(addr->a4);
-}
-
-static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
-{
-       return ntohl(addr->a6[2]^addr->a6[3]);
-}
-
-static inline unsigned int __xfrm_dst_hash(xfrm_address_t *addr,
-                                          u32 reqid, unsigned short family,
-                                          unsigned int hmask)
-{
-       unsigned int h = family ^ reqid;
-       switch (family) {
-       case AF_INET:
-               h ^= __xfrm4_addr_hash(addr);
-               break;
-       case AF_INET6:
-               h ^= __xfrm6_addr_hash(addr);
-               break;
-       };
-       return (h ^ (h >> 16)) & hmask;
-}
-
-static inline unsigned int xfrm_dst_hash(xfrm_address_t *addr, u32 reqid,
+static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
+                                        xfrm_address_t *saddr,
+                                        u32 reqid,
                                         unsigned short family)
 {
-       return __xfrm_dst_hash(addr, reqid, family, xfrm_state_hmask);
-}
-
-static inline unsigned __xfrm_src_hash(xfrm_address_t *addr, unsigned short family,
-                                      unsigned int hmask)
-{
-       unsigned int h = family;
-       switch (family) {
-       case AF_INET:
-               h ^= __xfrm4_addr_hash(addr);
-               break;
-       case AF_INET6:
-               h ^= __xfrm6_addr_hash(addr);
-               break;
-       };
-       return (h ^ (h >> 16)) & hmask;
+       return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
 }
 
-static inline unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family)
+static inline unsigned int xfrm_src_hash(xfrm_address_t *addr,
+                                        unsigned short family)
 {
        return __xfrm_src_hash(addr, family, xfrm_state_hmask);
 }
 
 static inline unsigned int
-__xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family,
-               unsigned int hmask)
+xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
 {
-       unsigned int h = spi ^ proto;
-       switch (family) {
-       case AF_INET:
-               h ^= __xfrm4_addr_hash(addr);
-               break;
-       case AF_INET6:
-               h ^= __xfrm6_addr_hash(addr);
-               break;
-       }
-       return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
-}
-
-static inline unsigned int
-xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family)
-{
-       return __xfrm_spi_hash(addr, spi, proto, family, xfrm_state_hmask);
-}
-
-static struct hlist_head *xfrm_state_hash_alloc(unsigned int sz)
-{
-       struct hlist_head *n;
-
-       if (sz <= PAGE_SIZE)
-               n = kmalloc(sz, GFP_KERNEL);
-       else if (hashdist)
-               n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL);
-       else
-               n = (struct hlist_head *)
-                       __get_free_pages(GFP_KERNEL, get_order(sz));
-
-       if (n)
-               memset(n, 0, sz);
-
-       return n;
-}
-
-static void xfrm_state_hash_free(struct hlist_head *n, unsigned int sz)
-{
-       if (sz <= PAGE_SIZE)
-               kfree(n);
-       else if (hashdist)
-               vfree(n);
-       else
-               free_pages((unsigned long)n, get_order(sz));
+       return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
 }
 
 static void xfrm_hash_transfer(struct hlist_head *list,
@@ -169,8 +87,9 @@ static void xfrm_hash_transfer(struct hlist_head *list,
        hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
                unsigned int h;
 
-               h = __xfrm_dst_hash(&x->id.daddr, x->props.reqid,
-                                   x->props.family, nhashmask);
+               h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
+                                   x->props.reqid, x->props.family,
+                                   nhashmask);
                hlist_add_head(&x->bydst, ndsttable+h);
 
                h = __xfrm_src_hash(&x->props.saddr, x->props.family,
@@ -201,18 +120,18 @@ static void xfrm_hash_resize(void *__unused)
        mutex_lock(&hash_resize_mutex);
 
        nsize = xfrm_hash_new_size();
-       ndst = xfrm_state_hash_alloc(nsize);
+       ndst = xfrm_hash_alloc(nsize);
        if (!ndst)
                goto out_unlock;
-       nsrc = xfrm_state_hash_alloc(nsize);
+       nsrc = xfrm_hash_alloc(nsize);
        if (!nsrc) {
-               xfrm_state_hash_free(ndst, nsize);
+               xfrm_hash_free(ndst, nsize);
                goto out_unlock;
        }
-       nspi = xfrm_state_hash_alloc(nsize);
+       nspi = xfrm_hash_alloc(nsize);
        if (!nspi) {
-               xfrm_state_hash_free(ndst, nsize);
-               xfrm_state_hash_free(nsrc, nsize);
+               xfrm_hash_free(ndst, nsize);
+               xfrm_hash_free(nsrc, nsize);
                goto out_unlock;
        }
 
@@ -236,9 +155,9 @@ static void xfrm_hash_resize(void *__unused)
        spin_unlock_bh(&xfrm_state_lock);
 
        osize = (ohashmask + 1) * sizeof(struct hlist_head);
-       xfrm_state_hash_free(odst, osize);
-       xfrm_state_hash_free(osrc, osize);
-       xfrm_state_hash_free(ospi, osize);
+       xfrm_hash_free(odst, osize);
+       xfrm_hash_free(osrc, osize);
+       xfrm_hash_free(ospi, osize);
 
 out_unlock:
        mutex_unlock(&hash_resize_mutex);
@@ -465,7 +384,7 @@ void xfrm_state_flush(u8 proto)
        int i;
 
        spin_lock_bh(&xfrm_state_lock);
-       for (i = 0; i < xfrm_state_hmask; i++) {
+       for (i = 0; i <= xfrm_state_hmask; i++) {
                struct hlist_node *entry;
                struct xfrm_state *x;
 restart:
@@ -502,7 +421,7 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
        return 0;
 }
 
-static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
+static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
 {
        unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
        struct xfrm_state *x;
@@ -587,7 +506,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
                struct xfrm_policy *pol, int *err,
                unsigned short family)
 {
-       unsigned int h = xfrm_dst_hash(daddr, tmpl->reqid, family);
+       unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
        struct hlist_node *entry;
        struct xfrm_state *x, *x0;
        int acquire_in_progress = 0;
@@ -696,7 +615,8 @@ static void __xfrm_state_insert(struct xfrm_state *x)
 
        x->genid = ++xfrm_state_genid;
 
-       h = xfrm_dst_hash(&x->id.daddr, x->props.reqid, x->props.family);
+       h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
+                         x->props.reqid, x->props.family);
        hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 
        h = xfrm_src_hash(&x->props.saddr, x->props.family);
@@ -732,11 +652,12 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
        struct hlist_node *entry;
        unsigned int h;
 
-       h = xfrm_dst_hash(&xnew->id.daddr, reqid, family);
+       h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
        hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
                if (x->props.family     == family &&
                    x->props.reqid      == reqid &&
-                   !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family))
+                   !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
+                   !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
                        x->genid = xfrm_state_genid;
        }
 }
@@ -753,7 +674,7 @@ EXPORT_SYMBOL(xfrm_state_insert);
 /* xfrm_state_lock is held */
 static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
 {
-       unsigned int h = xfrm_dst_hash(daddr, reqid, family);
+       unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
        struct hlist_node *entry;
        struct xfrm_state *x;
 
@@ -995,7 +916,7 @@ err:
 EXPORT_SYMBOL(xfrm_state_check);
 
 struct xfrm_state *
-xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
+xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
                  unsigned short family)
 {
        struct xfrm_state *x;
@@ -1119,7 +1040,7 @@ u32 xfrm_get_acqseq(void)
 EXPORT_SYMBOL(xfrm_get_acqseq);
 
 void
-xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
+xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi)
 {
        unsigned int h;
        struct xfrm_state *x0;
@@ -1136,10 +1057,10 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
                x->id.spi = minspi;
        } else {
                u32 spi = 0;
-               minspi = ntohl(minspi);
-               maxspi = ntohl(maxspi);
-               for (h=0; h<maxspi-minspi+1; h++) {
-                       spi = minspi + net_random()%(maxspi-minspi+1);
+               u32 low = ntohl(minspi);
+               u32 high = ntohl(maxspi);
+               for (h=0; h<high-low+1; h++) {
+                       spi = low + net_random()%(high-low+1);
                        x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
                        if (x0 == NULL) {
                                x->id.spi = htonl(spi);
@@ -1259,11 +1180,10 @@ static void xfrm_replay_timer_handler(unsigned long data)
        spin_unlock(&x->lock);
 }
 
-int xfrm_replay_check(struct xfrm_state *x, u32 seq)
+int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
 {
        u32 diff;
-
-       seq = ntohl(seq);
+       u32 seq = ntohl(net_seq);
 
        if (unlikely(seq == 0))
                return -EINVAL;
@@ -1626,9 +1546,9 @@ void __init xfrm_state_init(void)
 
        sz = sizeof(struct hlist_head) * 8;
 
-       xfrm_state_bydst = xfrm_state_hash_alloc(sz);
-       xfrm_state_bysrc = xfrm_state_hash_alloc(sz);
-       xfrm_state_byspi = xfrm_state_hash_alloc(sz);
+       xfrm_state_bydst = xfrm_hash_alloc(sz);
+       xfrm_state_bysrc = xfrm_hash_alloc(sz);
+       xfrm_state_byspi = xfrm_hash_alloc(sz);
        if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
                panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
        xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);