|
@@ -656,15 +656,23 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
|
|
|
EXPORT_SYMBOL(xfrm_sad_getinfo);
|
|
|
|
|
|
static int
|
|
|
-xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
|
|
|
- struct xfrm_tmpl *tmpl,
|
|
|
- xfrm_address_t *daddr, xfrm_address_t *saddr,
|
|
|
- unsigned short family)
|
|
|
+xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl,
|
|
|
+ struct xfrm_tmpl *tmpl,
|
|
|
+ xfrm_address_t *daddr, xfrm_address_t *saddr,
|
|
|
+ unsigned short family)
|
|
|
{
|
|
|
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
|
|
|
if (!afinfo)
|
|
|
return -1;
|
|
|
- afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
|
|
|
+ afinfo->init_tempsel(&x->sel, fl);
|
|
|
+
|
|
|
+ if (family != tmpl->encap_family) {
|
|
|
+ xfrm_state_put_afinfo(afinfo);
|
|
|
+ afinfo = xfrm_state_get_afinfo(tmpl->encap_family);
|
|
|
+ if (!afinfo)
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ afinfo->init_temprop(x, tmpl, daddr, saddr);
|
|
|
xfrm_state_put_afinfo(afinfo);
|
|
|
return 0;
|
|
|
}
|
|
@@ -790,37 +798,38 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
|
|
|
int error = 0;
|
|
|
struct xfrm_state *best = NULL;
|
|
|
u32 mark = pol->mark.v & pol->mark.m;
|
|
|
+ unsigned short encap_family = tmpl->encap_family;
|
|
|
|
|
|
to_put = NULL;
|
|
|
|
|
|
spin_lock_bh(&xfrm_state_lock);
|
|
|
- h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family);
|
|
|
+ h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
|
|
|
hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
|
|
|
- if (x->props.family == family &&
|
|
|
+ if (x->props.family == encap_family &&
|
|
|
x->props.reqid == tmpl->reqid &&
|
|
|
(mark & x->mark.m) == x->mark.v &&
|
|
|
!(x->props.flags & XFRM_STATE_WILDRECV) &&
|
|
|
- xfrm_state_addr_check(x, daddr, saddr, family) &&
|
|
|
+ xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
|
|
|
tmpl->mode == x->props.mode &&
|
|
|
tmpl->id.proto == x->id.proto &&
|
|
|
(tmpl->id.spi == x->id.spi || !tmpl->id.spi))
|
|
|
- xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
|
|
|
+ xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr,
|
|
|
&best, &acquire_in_progress, &error);
|
|
|
}
|
|
|
if (best)
|
|
|
goto found;
|
|
|
|
|
|
- h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
|
|
|
+ h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
|
|
|
hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) {
|
|
|
- if (x->props.family == family &&
|
|
|
+ if (x->props.family == encap_family &&
|
|
|
x->props.reqid == tmpl->reqid &&
|
|
|
(mark & x->mark.m) == x->mark.v &&
|
|
|
!(x->props.flags & XFRM_STATE_WILDRECV) &&
|
|
|
- xfrm_state_addr_check(x, daddr, saddr, family) &&
|
|
|
+ xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
|
|
|
tmpl->mode == x->props.mode &&
|
|
|
tmpl->id.proto == x->id.proto &&
|
|
|
(tmpl->id.spi == x->id.spi || !tmpl->id.spi))
|
|
|
- xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
|
|
|
+ xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr,
|
|
|
&best, &acquire_in_progress, &error);
|
|
|
}
|
|
|
|
|
@@ -829,7 +838,7 @@ found:
|
|
|
if (!x && !error && !acquire_in_progress) {
|
|
|
if (tmpl->id.spi &&
|
|
|
(x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
|
|
|
- tmpl->id.proto, family)) != NULL) {
|
|
|
+ tmpl->id.proto, encap_family)) != NULL) {
|
|
|
to_put = x0;
|
|
|
error = -EEXIST;
|
|
|
goto out;
|
|
@@ -839,9 +848,9 @@ found:
|
|
|
error = -ENOMEM;
|
|
|
goto out;
|
|
|
}
|
|
|
- /* Initialize temporary selector matching only
|
|
|
+ /* Initialize temporary state matching only
|
|
|
* to current session. */
|
|
|
- xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
|
|
|
+ xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
|
|
|
memcpy(&x->mark, &pol->mark, sizeof(x->mark));
|
|
|
|
|
|
error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
|
|
@@ -856,10 +865,10 @@ found:
|
|
|
x->km.state = XFRM_STATE_ACQ;
|
|
|
list_add(&x->km.all, &net->xfrm.state_all);
|
|
|
hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
|
|
|
- h = xfrm_src_hash(net, daddr, saddr, family);
|
|
|
+ h = xfrm_src_hash(net, daddr, saddr, encap_family);
|
|
|
hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
|
|
|
if (x->id.spi) {
|
|
|
- h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family);
|
|
|
+ h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
|
|
|
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
|
|
|
}
|
|
|
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
|