--- a/include/net/xfrm.h 2005/04/28 14:05:00 1.1 +++ b/include/net/xfrm.h 2005/04/28 14:05:48 @@ -302,6 +302,7 @@ struct dst_entry *bundles; __u16 family; __u8 action; + __u8 dir; __u8 flags; __u8 dead; __u8 xfrm_nr; --- a/net/xfrm/xfrm_user.c 2005/04/28 13:59:27 1.1 +++ b/net/xfrm/xfrm_user.c 2005/04/28 14:01:58 @@ -653,6 +653,7 @@ memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); xp->action = p->action; + xp->dir = p->dir; xp->flags = p->flags; xp->family = p->sel.family; /* XXX xp->share = p->share; */ --- a/net/xfrm/xfrm_policy.c 2005/04/27 11:32:13 1.1 +++ b/net/xfrm/xfrm_policy.c 2005/04/29 23:07:38 @@ -163,7 +163,7 @@ if (xp->dead) goto out; - dir = xp->index & 7; + dir = xp->dir; if (xp->lft.hard_add_expires_seconds) { long tmo = xp->lft.hard_add_expires_seconds + @@ -341,17 +341,35 @@ { struct xfrm_policy *pol, **p; struct xfrm_policy *delpol = NULL; + struct xfrm_policy *delpol2 = NULL; + struct xfrm_policy *delp = NULL; struct xfrm_policy **newpos = NULL; + int ret = -EINVAL; + + if (policy->index) + delpol = xfrm_policy_byid(dir, policy->index, 0); + delpol2 = xfrm_policy_bysel(dir, &policy->selector, 0); + + /* must be unique in both index and selector */ + if (delpol && delpol2) + if (delpol != delpol2) + goto pol_err; + if (delpol) + delp = delpol; + else + delp = delpol2; + + if (delp && excl) { + ret = -EEXIST; + goto pol_err; + } + + /* insert, sorted by prio*/ write_lock_bh(&xfrm_policy_lock); for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { - if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { - if (excl) { - write_unlock_bh(&xfrm_policy_lock); - return -EEXIST; - } + if (pol == delp) { *p = pol->next; - delpol = pol; if (policy->priority > pol->priority) continue; } else if (policy->priority >= pol->priority) { @@ -360,27 +378,36 @@ } if (!newpos) newpos = p; - if (delpol) - break; p = &pol->next; } + if (newpos) p = newpos; + xfrm_pol_hold(policy); policy->next = *p; *p = policy; atomic_inc(&flow_cache_genid); - policy->index = delpol ? delpol->index : xfrm_gen_index(dir); + if (!policy->index) + policy->index = delp ? delp->index : xfrm_gen_index(dir); + policy->curlft.add_time = (unsigned long)xtime.tv_sec; policy->curlft.use_time = 0; if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); write_unlock_bh(&xfrm_policy_lock); - if (delpol) { - xfrm_policy_kill(delpol); + if (delp) { + xfrm_policy_kill(delp); } - return 0; + ret = 0; + +pol_err: + if (delpol) + xfrm_pol_put(delpol); + if (delpol2) + xfrm_pol_put(delpol2); + return ret; } EXPORT_SYMBOL(xfrm_policy_insert); @@ -413,7 +440,7 @@ struct xfrm_policy *pol, **p; write_lock_bh(&xfrm_policy_lock); - for (p = &xfrm_policy_list[id & 7]; (pol=*p)!=NULL; p = &pol->next) { + for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { if (pol->index == id) { xfrm_pol_hold(pol); if (delete)