|
@@ -594,6 +594,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
|
|
|
|
|
|
xfrm_smark_init(attrs, &x->props.smark);
|
|
|
|
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
|
+ x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
+
|
|
|
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
|
|
|
if (err)
|
|
|
goto error;
|
|
@@ -929,7 +932,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
|
|
|
ret = copy_user_offload(&x->xso, skb);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
-
|
|
|
+ if (x->if_id) {
|
|
|
+ ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
if (x->security)
|
|
|
ret = copy_sec_ctx(x->security, skb);
|
|
|
out:
|
|
@@ -1278,6 +1285,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
int err;
|
|
|
u32 mark;
|
|
|
struct xfrm_mark m;
|
|
|
+ u32 if_id = 0;
|
|
|
|
|
|
p = nlmsg_data(nlh);
|
|
|
err = verify_spi_info(p->info.id.proto, p->min, p->max);
|
|
@@ -1290,6 +1298,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
x = NULL;
|
|
|
|
|
|
mark = xfrm_mark_get(attrs, &m);
|
|
|
+
|
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
|
+ if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
+
|
|
|
if (p->info.seq) {
|
|
|
x = xfrm_find_acq_byseq(net, mark, p->info.seq);
|
|
|
if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) {
|
|
@@ -1300,7 +1312,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
|
|
if (!x)
|
|
|
x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
|
|
|
- p->info.id.proto, daddr,
|
|
|
+ if_id, p->info.id.proto, daddr,
|
|
|
&p->info.saddr, 1,
|
|
|
family);
|
|
|
err = -ENOENT;
|
|
@@ -1588,6 +1600,9 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
|
|
|
|
|
|
xfrm_mark_get(attrs, &xp->mark);
|
|
|
|
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
|
+ xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
+
|
|
|
return xp;
|
|
|
error:
|
|
|
*errp = err;
|
|
@@ -1733,6 +1748,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
if (!err)
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
|
|
+ if (!err)
|
|
|
+ err = xfrm_if_id_put(skb, xp->if_id);
|
|
|
if (err) {
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
return err;
|
|
@@ -1814,6 +1831,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
int delete;
|
|
|
struct xfrm_mark m;
|
|
|
u32 mark = xfrm_mark_get(attrs, &m);
|
|
|
+ u32 if_id = 0;
|
|
|
|
|
|
p = nlmsg_data(nlh);
|
|
|
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
|
|
@@ -1826,8 +1844,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
|
+ if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
+
|
|
|
if (p->index)
|
|
|
- xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err);
|
|
|
+ xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, delete, &err);
|
|
|
else {
|
|
|
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
|
|
|
struct xfrm_sec_ctx *ctx;
|
|
@@ -1844,7 +1865,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
if (err)
|
|
|
return err;
|
|
|
}
|
|
|
- xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel,
|
|
|
+ xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, &p->sel,
|
|
|
ctx, delete, &err);
|
|
|
security_xfrm_policy_free(ctx);
|
|
|
}
|
|
@@ -1967,6 +1988,10 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
|
|
|
if (err)
|
|
|
goto out_cancel;
|
|
|
|
|
|
+ err = xfrm_if_id_put(skb, x->if_id);
|
|
|
+ if (err)
|
|
|
+ goto out_cancel;
|
|
|
+
|
|
|
nlmsg_end(skb, nlh);
|
|
|
return 0;
|
|
|
|
|
@@ -2109,6 +2134,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
int err = -ENOENT;
|
|
|
struct xfrm_mark m;
|
|
|
u32 mark = xfrm_mark_get(attrs, &m);
|
|
|
+ u32 if_id = 0;
|
|
|
|
|
|
err = copy_from_user_policy_type(&type, attrs);
|
|
|
if (err)
|
|
@@ -2118,8 +2144,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ if (attrs[XFRMA_IF_ID])
|
|
|
+ if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
+
|
|
|
if (p->index)
|
|
|
- xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err);
|
|
|
+ xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, 0, &err);
|
|
|
else {
|
|
|
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
|
|
|
struct xfrm_sec_ctx *ctx;
|
|
@@ -2136,7 +2165,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
if (err)
|
|
|
return err;
|
|
|
}
|
|
|
- xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir,
|
|
|
+ xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir,
|
|
|
&p->sel, ctx, 0, &err);
|
|
|
security_xfrm_policy_free(ctx);
|
|
|
}
|
|
@@ -2520,6 +2549,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
|
|
|
[XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) },
|
|
|
[XFRMA_SET_MARK] = { .type = NLA_U32 },
|
|
|
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
|
|
|
+ [XFRMA_IF_ID] = { .type = NLA_U32 },
|
|
|
};
|
|
|
|
|
|
static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
|
|
@@ -2651,6 +2681,10 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ err = xfrm_if_id_put(skb, x->if_id);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
nlmsg_end(skb, nlh);
|
|
|
return 0;
|
|
|
}
|
|
@@ -2749,6 +2783,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
|
|
|
l += nla_total_size(sizeof(x->props.smark.v));
|
|
|
l += nla_total_size(sizeof(x->props.smark.m));
|
|
|
}
|
|
|
+ if (x->if_id)
|
|
|
+ l += nla_total_size(sizeof(x->if_id));
|
|
|
|
|
|
/* Must count x->lastused as it may become non-zero behind our back. */
|
|
|
l += nla_total_size_64bit(sizeof(u64));
|
|
@@ -2878,6 +2914,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
if (!err)
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
|
|
+ if (!err)
|
|
|
+ err = xfrm_if_id_put(skb, xp->if_id);
|
|
|
if (err) {
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
return err;
|
|
@@ -2994,6 +3032,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
if (!err)
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
|
|
+ if (!err)
|
|
|
+ err = xfrm_if_id_put(skb, xp->if_id);
|
|
|
if (err) {
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
return err;
|
|
@@ -3075,6 +3115,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
if (!err)
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
|
|
+ if (!err)
|
|
|
+ err = xfrm_if_id_put(skb, xp->if_id);
|
|
|
if (err)
|
|
|
goto out_free_skb;
|
|
|
|