aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-02-17 23:29:30 -0800
committerDavid S. Miller <davem@davemloft.net>2008-02-17 23:29:30 -0800
commitb791160b5af4ea95c72fb59d13079664beca1963 (patch)
tree7c5b3e4d4875c002c8315c05ced0e16392eb2a30 /net/xfrm
parent82453021b8be85171350c695d7ebafe7b517c812 (diff)
downloadkernel_samsung_tuna-b791160b5af4ea95c72fb59d13079664beca1963.zip
kernel_samsung_tuna-b791160b5af4ea95c72fb59d13079664beca1963.tar.gz
kernel_samsung_tuna-b791160b5af4ea95c72fb59d13079664beca1963.tar.bz2
[XFRM]: Fix ordering issue in xfrm_dst_hash_transfer().
Keep ordering of policy entries with same selector in xfrm_dst_hash_transfer(). Issue should not appear in usual cases because multiple policy entries with same selector are basically not allowed so far. Bug was pointed out by Sebastien Decugis <sdecugis@hongo.wide.ad.jp>. We could convert bydst from hlist to list and use list_add_tail() instead. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Acked-by: Sebastien Decugis <sdecugis@hongo.wide.ad.jp> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 47219f9..9fc4c31 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -331,15 +331,31 @@ static void xfrm_dst_hash_transfer(struct hlist_head *list,
struct hlist_head *ndsttable,
unsigned int nhashmask)
{
- struct hlist_node *entry, *tmp;
+ struct hlist_node *entry, *tmp, *entry0 = NULL;
struct xfrm_policy *pol;
+ unsigned int h0 = 0;
+redo:
hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) {
unsigned int h;
h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
pol->family, nhashmask);
- hlist_add_head(&pol->bydst, ndsttable+h);
+ if (!entry0) {
+ hlist_del(entry);
+ hlist_add_head(&pol->bydst, ndsttable+h);
+ h0 = h;
+ } else {
+ if (h != h0)
+ continue;
+ hlist_del(entry);
+ hlist_add_after(entry0, &pol->bydst);
+ }
+ entry0 = entry;
+ }
+ if (!hlist_empty(list)) {
+ entry0 = NULL;
+ goto redo;
}
}