xfrm_address_t *daddr, *saddr;
struct hlist_node *entry;
struct hlist_head *chain;
+ u32 priority = ~0U;
daddr = xfrm_flowi_daddr(fl, family);
saddr = xfrm_flowi_saddr(fl, family);
ret = NULL;
hlist_for_each_entry(pol, entry, chain, bydst) {
if (xfrm_policy_match(pol, fl, type, family, dir)) {
- xfrm_pol_hold(pol);
ret = pol;
+ priority = ret->priority;
break;
}
}
- if (!ret) {
- chain = &xfrm_policy_inexact[dir];
- hlist_for_each_entry(pol, entry, chain, bydst) {
- if (xfrm_policy_match(pol, fl, type, family, dir)) {
- xfrm_pol_hold(pol);
- ret = pol;
- break;
- }
+ chain = &xfrm_policy_inexact[dir];
+ hlist_for_each_entry(pol, entry, chain, bydst) {
+ if (xfrm_policy_match(pol, fl, type, family, dir) &&
+ pol->priority < priority) {
+ ret = pol;
+ break;
}
}
+ if (ret)
+ xfrm_pol_hold(ret);
read_unlock_bh(&xfrm_policy_lock);
return ret;
return 0;
}
+static int
+xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,
+ unsigned short family)
+{
+ int err;
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+
+ if (unlikely(afinfo == NULL))
+ return -EINVAL;
+ err = afinfo->get_saddr(local, remote);
+ xfrm_policy_put_afinfo(afinfo);
+ return err;
+}
+
/* Resolve list of templates for the flow, given policy. */
static int
int i, error;
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
+ xfrm_address_t tmp;
for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
struct xfrm_state *x;
if (tmpl->mode == XFRM_MODE_TUNNEL) {
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
+ if (xfrm_addr_any(local, family)) {
+ error = xfrm_get_saddr(&tmp, remote, family);
+ if (error)
+ goto fail;
+ local = &tmp;
+ }
}
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
{
for (; k < sp->len; k++) {
if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
- if (idxp)
- *idxp = k;
+ *idxp = k;
return 1;
}
}
struct flowi fl;
u8 fl_dir = policy_to_flow_dir(dir);
int xerr_idx = -1;
- int *xerr_idxp = &xerr_idx;
if (xfrm_decode_session(skb, &fl, family) < 0)
return 0;
xfrm_policy_lookup);
if (!pol) {
- if (skb->sp && secpath_has_nontransport(skb->sp, 0, xerr_idxp)) {
+ if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
xfrm_secpath_reject(xerr_idx, skb, &fl);
return 0;
}
for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
k = xfrm_policy_ok(tpp[i], sp, k, family);
if (k < 0) {
- if (k < -1 && xerr_idxp)
- *xerr_idxp = -(2+k);
+ if (k < -1)
+ /* "-2 - errored_index" returned */
+ xerr_idx = -(2+k);
goto reject;
}
}
- if (secpath_has_nontransport(sp, k, xerr_idxp))
+ if (secpath_has_nontransport(sp, k, &xerr_idx))
goto reject;
xfrm_pols_put(pols, npols);
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
sizeof(struct xfrm_dst),
- 0, SLAB_HWCACHE_ALIGN,
+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL, NULL);
- if (!xfrm_dst_cache)
- panic("XFRM: failed to allocate xfrm_dst_cache\n");
hmask = 8 - 1;
sz = (hmask+1) * sizeof(struct hlist_head);