xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x,
unsigned short family)
{
+ if (xfrm_state_kern(x))
+ return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, family);
return x->id.proto == tmpl->id.proto &&
(x->id.spi == tmpl->id.spi || !tmpl->id.spi) &&
(x->props.reqid == tmpl->reqid || !tmpl->reqid) &&
}
static inline int
-xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int idx,
+xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
unsigned short family)
{
+ int idx = start;
+
+ if (tmpl->optional) {
+ if (!tmpl->mode)
+ return start;
+ } else
+ start = -1;
for (; idx < sp->len; idx++) {
if (xfrm_state_ok(tmpl, sp->x[idx].xvec, family))
return ++idx;
+ if (sp->x[idx].xvec->props.mode)
+ break;
}
- return -1;
+ return start;
}
static int
xfrm_policy_lookup);
if (!pol)
- return 1;
+ return !skb->sp;
pol->curlft.use_time = (unsigned long)xtime.tv_sec;
if (pol->action == XFRM_POLICY_ALLOW) {
- if (pol->xfrm_nr != 0) {
- struct sec_path *sp;
- static struct sec_path dummy;
- int i, k;
-
- if ((sp = skb->sp) == NULL)
- sp = &dummy;
-
- /* For each tmpl search corresponding xfrm.
- * Order is _important_. Later we will implement
- * some barriers, but at the moment barriers
- * are implied between each two transformations.
- */
- for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) {
- if (pol->xfrm_vec[i].optional)
- continue;
- k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family);
- if (k < 0)
- goto reject;
- }
+ struct sec_path *sp;
+ static struct sec_path dummy;
+ int i, k;
+
+ if ((sp = skb->sp) == NULL)
+ sp = &dummy;
+
+ /* For each tunnel xfrm, find the first matching tmpl.
+ * For each tmpl before that, find corresponding xfrm.
+ * Order is _important_. Later we will implement
+ * some barriers, but at the moment barriers
+ * are implied between each two transformations.
+ */
+ for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) {
+ k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family);
+ if (k < 0)
+ goto reject;
+ }
+
+ for (; k < sp->len; k++) {
+ if (sp->x[k].xvec->props.mode)
+ goto reject;
}
+
xfrm_pol_put(pol);
return 1;
}