Commit 7e652640 authored by Steffen Klassert's avatar Steffen Klassert

xfrm: Add a new lookup key to match xfrm interfaces.

This patch adds the xfrm interface id as a lookup key
for xfrm states and policies. With this we can assign
states and policies to virtual xfrm interfaces.
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
Acked-by: default avatarShannon Nelson <shannon.nelson@oracle.com>
Acked-by: default avatarBenedict Wong <benedictwong@google.com>
Tested-by: default avatarBenedict Wong <benedictwong@google.com>
Tested-by: default avatarAntony Antony <antony@phenome.org>
Reviewed-by: default avatarEyal Birger <eyal.birger@gmail.com>
parent d159ce79
...@@ -147,6 +147,7 @@ struct xfrm_state { ...@@ -147,6 +147,7 @@ struct xfrm_state {
struct xfrm_id id; struct xfrm_id id;
struct xfrm_selector sel; struct xfrm_selector sel;
struct xfrm_mark mark; struct xfrm_mark mark;
u32 if_id;
u32 tfcpad; u32 tfcpad;
u32 genid; u32 genid;
...@@ -574,6 +575,7 @@ struct xfrm_policy { ...@@ -574,6 +575,7 @@ struct xfrm_policy {
atomic_t genid; atomic_t genid;
u32 priority; u32 priority;
u32 index; u32 index;
u32 if_id;
struct xfrm_mark mark; struct xfrm_mark mark;
struct xfrm_selector selector; struct xfrm_selector selector;
struct xfrm_lifetime_cfg lft; struct xfrm_lifetime_cfg lft;
...@@ -1533,7 +1535,7 @@ struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, ...@@ -1533,7 +1535,7 @@ struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
struct xfrm_tmpl *tmpl, struct xfrm_tmpl *tmpl,
struct xfrm_policy *pol, int *err, struct xfrm_policy *pol, int *err,
unsigned short family); unsigned short family);
struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
xfrm_address_t *daddr, xfrm_address_t *daddr,
xfrm_address_t *saddr, xfrm_address_t *saddr,
unsigned short family, unsigned short family,
...@@ -1690,20 +1692,20 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, ...@@ -1690,20 +1692,20 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
void *); void *);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
u8 type, int dir, u8 type, int dir,
struct xfrm_selector *sel, struct xfrm_selector *sel,
struct xfrm_sec_ctx *ctx, int delete, struct xfrm_sec_ctx *ctx, int delete,
int *err); int *err);
struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id, u8,
u32 id, int delete, int *err); int dir, u32 id, int delete, int *err);
int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
void xfrm_policy_hash_rebuild(struct net *net); void xfrm_policy_hash_rebuild(struct net *net);
u32 xfrm_get_acqseq(void); u32 xfrm_get_acqseq(void);
int verify_spi_info(u8 proto, u32 min, u32 max); int verify_spi_info(u8 proto, u32 min, u32 max);
int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark,
u8 mode, u32 reqid, u8 proto, u8 mode, u32 reqid, u32 if_id, u8 proto,
const xfrm_address_t *daddr, const xfrm_address_t *daddr,
const xfrm_address_t *saddr, int create, const xfrm_address_t *saddr, int create,
unsigned short family); unsigned short family);
...@@ -2019,6 +2021,15 @@ static inline __u32 xfrm_smark_get(__u32 mark, struct xfrm_state *x) ...@@ -2019,6 +2021,15 @@ static inline __u32 xfrm_smark_get(__u32 mark, struct xfrm_state *x)
return (m->v & m->m) | (mark & ~m->m); return (m->v & m->m) | (mark & ~m->m);
} }
static inline int xfrm_if_id_put(struct sk_buff *skb, __u32 if_id)
{
int ret = 0;
if (if_id)
ret = nla_put_u32(skb, XFRMA_IF_ID, if_id);
return ret;
}
static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
unsigned int family) unsigned int family)
{ {
......
...@@ -307,6 +307,7 @@ enum xfrm_attr_type_t { ...@@ -307,6 +307,7 @@ enum xfrm_attr_type_t {
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
XFRMA_SET_MARK, /* __u32 */ XFRMA_SET_MARK, /* __u32 */
XFRMA_SET_MARK_MASK, /* __u32 */ XFRMA_SET_MARK_MASK, /* __u32 */
XFRMA_IF_ID, /* __u32 */
__XFRMA_MAX __XFRMA_MAX
#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
......
...@@ -2255,7 +2255,7 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) ...@@ -2255,7 +2255,7 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
} else { } else {
/* slow path: we dont already have xfrm_state */ /* slow path: we dont already have xfrm_state */
x = xfrm_stateonly_find(pn->net, DUMMY_MARK, x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0,
(xfrm_address_t *)&pkt_dev->cur_daddr, (xfrm_address_t *)&pkt_dev->cur_daddr,
(xfrm_address_t *)&pkt_dev->cur_saddr, (xfrm_address_t *)&pkt_dev->cur_saddr,
AF_INET, AF_INET,
......
...@@ -1383,7 +1383,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_ ...@@ -1383,7 +1383,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_
} }
if (!x) if (!x)
x = xfrm_find_acq(net, &dummy_mark, mode, reqid, proto, xdaddr, xsaddr, 1, family); x = xfrm_find_acq(net, &dummy_mark, mode, reqid, 0, proto, xdaddr, xsaddr, 1, family);
if (x == NULL) if (x == NULL)
return -ENOENT; return -ENOENT;
...@@ -2414,7 +2414,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa ...@@ -2414,7 +2414,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
return err; return err;
} }
xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN,
pol->sadb_x_policy_dir - 1, &sel, pol_ctx, pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
1, &err); 1, &err);
security_xfrm_policy_free(pol_ctx); security_xfrm_policy_free(pol_ctx);
...@@ -2663,7 +2663,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_ ...@@ -2663,7 +2663,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_
return -EINVAL; return -EINVAL;
delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, xp = xfrm_policy_byid(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN,
dir, pol->sadb_x_policy_id, delete, &err); dir, pol->sadb_x_policy_id, delete, &err);
if (xp == NULL) if (xp == NULL)
return -ENOENT; return -ENOENT;
......
...@@ -747,6 +747,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -747,6 +747,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
newpos = NULL; newpos = NULL;
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
if (pol->type == policy->type && if (pol->type == policy->type &&
pol->if_id == policy->if_id &&
!selector_cmp(&pol->selector, &policy->selector) && !selector_cmp(&pol->selector, &policy->selector) &&
xfrm_policy_mark_match(policy, pol) && xfrm_policy_mark_match(policy, pol) &&
xfrm_sec_ctx_match(pol->security, policy->security) && xfrm_sec_ctx_match(pol->security, policy->security) &&
...@@ -798,8 +799,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -798,8 +799,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
} }
EXPORT_SYMBOL(xfrm_policy_insert); EXPORT_SYMBOL(xfrm_policy_insert);
struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
int dir, struct xfrm_selector *sel, u8 type, int dir,
struct xfrm_selector *sel,
struct xfrm_sec_ctx *ctx, int delete, struct xfrm_sec_ctx *ctx, int delete,
int *err) int *err)
{ {
...@@ -812,6 +814,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, ...@@ -812,6 +814,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
ret = NULL; ret = NULL;
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
if (pol->type == type && if (pol->type == type &&
pol->if_id == if_id &&
(mark & pol->mark.m) == pol->mark.v && (mark & pol->mark.m) == pol->mark.v &&
!selector_cmp(sel, &pol->selector) && !selector_cmp(sel, &pol->selector) &&
xfrm_sec_ctx_match(ctx, pol->security)) { xfrm_sec_ctx_match(ctx, pol->security)) {
...@@ -837,8 +840,9 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, ...@@ -837,8 +840,9 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
} }
EXPORT_SYMBOL(xfrm_policy_bysel_ctx); EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id,
int dir, u32 id, int delete, int *err) u8 type, int dir, u32 id, int delete,
int *err)
{ {
struct xfrm_policy *pol, *ret; struct xfrm_policy *pol, *ret;
struct hlist_head *chain; struct hlist_head *chain;
...@@ -853,6 +857,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, ...@@ -853,6 +857,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
ret = NULL; ret = NULL;
hlist_for_each_entry(pol, chain, byidx) { hlist_for_each_entry(pol, chain, byidx) {
if (pol->type == type && pol->index == id && if (pol->type == type && pol->index == id &&
pol->if_id == if_id &&
(mark & pol->mark.m) == pol->mark.v) { (mark & pol->mark.m) == pol->mark.v) {
xfrm_pol_hold(pol); xfrm_pol_hold(pol);
if (delete) { if (delete) {
...@@ -1063,6 +1068,7 @@ static int xfrm_policy_match(const struct xfrm_policy *pol, ...@@ -1063,6 +1068,7 @@ static int xfrm_policy_match(const struct xfrm_policy *pol,
bool match; bool match;
if (pol->family != family || if (pol->family != family ||
pol->if_id != fl->flowi_xfrm.if_id ||
(fl->flowi_mark & pol->mark.m) != pol->mark.v || (fl->flowi_mark & pol->mark.m) != pol->mark.v ||
pol->type != type) pol->type != type)
return ret; return ret;
...@@ -1177,7 +1183,8 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, ...@@ -1177,7 +1183,8 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
match = xfrm_selector_match(&pol->selector, fl, family); match = xfrm_selector_match(&pol->selector, fl, family);
if (match) { if (match) {
if ((sk->sk_mark & pol->mark.m) != pol->mark.v) { if ((sk->sk_mark & pol->mark.m) != pol->mark.v ||
pol->if_id != fl->flowi_xfrm.if_id) {
pol = NULL; pol = NULL;
goto out; goto out;
} }
...@@ -1305,6 +1312,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) ...@@ -1305,6 +1312,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
newp->lft = old->lft; newp->lft = old->lft;
newp->curlft = old->curlft; newp->curlft = old->curlft;
newp->mark = old->mark; newp->mark = old->mark;
newp->if_id = old->if_id;
newp->action = old->action; newp->action = old->action;
newp->flags = old->flags; newp->flags = old->flags;
newp->xfrm_nr = old->xfrm_nr; newp->xfrm_nr = old->xfrm_nr;
......
...@@ -941,6 +941,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -941,6 +941,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
int error = 0; int error = 0;
struct xfrm_state *best = NULL; struct xfrm_state *best = NULL;
u32 mark = pol->mark.v & pol->mark.m; u32 mark = pol->mark.v & pol->mark.m;
u32 if_id = fl->flowi_xfrm.if_id;
unsigned short encap_family = tmpl->encap_family; unsigned short encap_family = tmpl->encap_family;
unsigned int sequence; unsigned int sequence;
struct km_event c; struct km_event c;
...@@ -955,6 +956,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -955,6 +956,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
if (x->props.family == encap_family && if (x->props.family == encap_family &&
x->props.reqid == tmpl->reqid && x->props.reqid == tmpl->reqid &&
(mark & x->mark.m) == x->mark.v && (mark & x->mark.m) == x->mark.v &&
x->if_id == if_id &&
!(x->props.flags & XFRM_STATE_WILDRECV) && !(x->props.flags & XFRM_STATE_WILDRECV) &&
xfrm_state_addr_check(x, daddr, saddr, encap_family) && xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
tmpl->mode == x->props.mode && tmpl->mode == x->props.mode &&
...@@ -971,6 +973,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -971,6 +973,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
if (x->props.family == encap_family && if (x->props.family == encap_family &&
x->props.reqid == tmpl->reqid && x->props.reqid == tmpl->reqid &&
(mark & x->mark.m) == x->mark.v && (mark & x->mark.m) == x->mark.v &&
x->if_id == if_id &&
!(x->props.flags & XFRM_STATE_WILDRECV) && !(x->props.flags & XFRM_STATE_WILDRECV) &&
xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && xfrm_addr_equal(&x->id.daddr, daddr, encap_family) &&
tmpl->mode == x->props.mode && tmpl->mode == x->props.mode &&
...@@ -1010,6 +1013,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -1010,6 +1013,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
* to current session. */ * to current session. */
xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
memcpy(&x->mark, &pol->mark, sizeof(x->mark)); memcpy(&x->mark, &pol->mark, sizeof(x->mark));
x->if_id = if_id;
error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid);
if (error) { if (error) {
...@@ -1067,7 +1071,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -1067,7 +1071,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
} }
struct xfrm_state * struct xfrm_state *
xfrm_stateonly_find(struct net *net, u32 mark, xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
xfrm_address_t *daddr, xfrm_address_t *saddr, xfrm_address_t *daddr, xfrm_address_t *saddr,
unsigned short family, u8 mode, u8 proto, u32 reqid) unsigned short family, u8 mode, u8 proto, u32 reqid)
{ {
...@@ -1080,6 +1084,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, ...@@ -1080,6 +1084,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
if (x->props.family == family && if (x->props.family == family &&
x->props.reqid == reqid && x->props.reqid == reqid &&
(mark & x->mark.m) == x->mark.v && (mark & x->mark.m) == x->mark.v &&
x->if_id == if_id &&
!(x->props.flags & XFRM_STATE_WILDRECV) && !(x->props.flags & XFRM_STATE_WILDRECV) &&
xfrm_state_addr_check(x, daddr, saddr, family) && xfrm_state_addr_check(x, daddr, saddr, family) &&
mode == x->props.mode && mode == x->props.mode &&
...@@ -1160,11 +1165,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) ...@@ -1160,11 +1165,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
struct xfrm_state *x; struct xfrm_state *x;
unsigned int h; unsigned int h;
u32 mark = xnew->mark.v & xnew->mark.m; u32 mark = xnew->mark.v & xnew->mark.m;
u32 if_id = xnew->if_id;
h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == family && if (x->props.family == family &&
x->props.reqid == reqid && x->props.reqid == reqid &&
x->if_id == if_id &&
(mark & x->mark.m) == x->mark.v && (mark & x->mark.m) == x->mark.v &&
xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) &&
xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family))
...@@ -1187,7 +1194,7 @@ EXPORT_SYMBOL(xfrm_state_insert); ...@@ -1187,7 +1194,7 @@ EXPORT_SYMBOL(xfrm_state_insert);
static struct xfrm_state *__find_acq_core(struct net *net, static struct xfrm_state *__find_acq_core(struct net *net,
const struct xfrm_mark *m, const struct xfrm_mark *m,
unsigned short family, u8 mode, unsigned short family, u8 mode,
u32 reqid, u8 proto, u32 reqid, u32 if_id, u8 proto,
const xfrm_address_t *daddr, const xfrm_address_t *daddr,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
int create) int create)
...@@ -1242,6 +1249,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, ...@@ -1242,6 +1249,7 @@ static struct xfrm_state *__find_acq_core(struct net *net,
x->props.family = family; x->props.family = family;
x->props.mode = mode; x->props.mode = mode;
x->props.reqid = reqid; x->props.reqid = reqid;
x->if_id = if_id;
x->mark.v = m->v; x->mark.v = m->v;
x->mark.m = m->m; x->mark.m = m->m;
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
...@@ -1296,7 +1304,7 @@ int xfrm_state_add(struct xfrm_state *x) ...@@ -1296,7 +1304,7 @@ int xfrm_state_add(struct xfrm_state *x)
if (use_spi && !x1) if (use_spi && !x1)
x1 = __find_acq_core(net, &x->mark, family, x->props.mode, x1 = __find_acq_core(net, &x->mark, family, x->props.mode,
x->props.reqid, x->id.proto, x->props.reqid, x->if_id, x->id.proto,
&x->id.daddr, &x->props.saddr, 0); &x->id.daddr, &x->props.saddr, 0);
__xfrm_state_bump_genids(x); __xfrm_state_bump_genids(x);
...@@ -1395,6 +1403,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, ...@@ -1395,6 +1403,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
x->props.flags = orig->props.flags; x->props.flags = orig->props.flags;
x->props.extra_flags = orig->props.extra_flags; x->props.extra_flags = orig->props.extra_flags;
x->if_id = orig->if_id;
x->tfcpad = orig->tfcpad; x->tfcpad = orig->tfcpad;
x->replay_maxdiff = orig->replay_maxdiff; x->replay_maxdiff = orig->replay_maxdiff;
x->replay_maxage = orig->replay_maxage; x->replay_maxage = orig->replay_maxage;
...@@ -1619,13 +1628,13 @@ EXPORT_SYMBOL(xfrm_state_lookup_byaddr); ...@@ -1619,13 +1628,13 @@ EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
struct xfrm_state * struct xfrm_state *
xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
u8 proto, const xfrm_address_t *daddr, u32 if_id, u8 proto, const xfrm_address_t *daddr,
const xfrm_address_t *saddr, int create, unsigned short family) const xfrm_address_t *saddr, int create, unsigned short family)
{ {
struct xfrm_state *x; struct xfrm_state *x;
spin_lock_bh(&net->xfrm.xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create);
spin_unlock_bh(&net->xfrm.xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x; return x;
......
...@@ -594,6 +594,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, ...@@ -594,6 +594,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
xfrm_smark_init(attrs, &x->props.smark); 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]); err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
if (err) if (err)
goto error; goto error;
...@@ -929,7 +932,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x, ...@@ -929,7 +932,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
ret = copy_user_offload(&x->xso, skb); ret = copy_user_offload(&x->xso, skb);
if (ret) if (ret)
goto out; goto out;
if (x->if_id) {
ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id);
if (ret)
goto out;
}
if (x->security) if (x->security)
ret = copy_sec_ctx(x->security, skb); ret = copy_sec_ctx(x->security, skb);
out: out:
...@@ -1278,6 +1285,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1278,6 +1285,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
int err; int err;
u32 mark; u32 mark;
struct xfrm_mark m; struct xfrm_mark m;
u32 if_id = 0;
p = nlmsg_data(nlh); p = nlmsg_data(nlh);
err = verify_spi_info(p->info.id.proto, p->min, p->max); 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, ...@@ -1290,6 +1298,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
x = NULL; x = NULL;
mark = xfrm_mark_get(attrs, &m); mark = xfrm_mark_get(attrs, &m);
if (attrs[XFRMA_IF_ID])
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
if (p->info.seq) { if (p->info.seq) {
x = xfrm_find_acq_byseq(net, mark, p->info.seq); x = xfrm_find_acq_byseq(net, mark, p->info.seq);
if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) { 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, ...@@ -1300,7 +1312,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!x) if (!x)
x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, 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, &p->info.saddr, 1,
family); family);
err = -ENOENT; err = -ENOENT;
...@@ -1588,6 +1600,9 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us ...@@ -1588,6 +1600,9 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
xfrm_mark_get(attrs, &xp->mark); xfrm_mark_get(attrs, &xp->mark);
if (attrs[XFRMA_IF_ID])
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
return xp; return xp;
error: error:
*errp = err; *errp = err;
...@@ -1733,6 +1748,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr ...@@ -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); err = copy_to_user_policy_type(xp->type, skb);
if (!err) if (!err)
err = xfrm_mark_put(skb, &xp->mark); err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
if (err) { if (err) {
nlmsg_cancel(skb, nlh); nlmsg_cancel(skb, nlh);
return err; return err;
...@@ -1814,6 +1831,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1814,6 +1831,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
int delete; int delete;
struct xfrm_mark m; struct xfrm_mark m;
u32 mark = xfrm_mark_get(attrs, &m); u32 mark = xfrm_mark_get(attrs, &m);
u32 if_id = 0;
p = nlmsg_data(nlh); p = nlmsg_data(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
...@@ -1826,8 +1844,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1826,8 +1844,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err) if (err)
return err; return err;
if (attrs[XFRMA_IF_ID])
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
if (p->index) 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 { else {
struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct nlattr *rt = attrs[XFRMA_SEC_CTX];
struct xfrm_sec_ctx *ctx; struct xfrm_sec_ctx *ctx;
...@@ -1844,7 +1865,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1844,7 +1865,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err) if (err)
return 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); ctx, delete, &err);
security_xfrm_policy_free(ctx); security_xfrm_policy_free(ctx);
} }
...@@ -1967,6 +1988,10 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct ...@@ -1967,6 +1988,10 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
if (err) if (err)
goto out_cancel; goto out_cancel;
err = xfrm_if_id_put(skb, x->if_id);
if (err)
goto out_cancel;
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
return 0; return 0;
...@@ -2109,6 +2134,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2109,6 +2134,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
int err = -ENOENT; int err = -ENOENT;
struct xfrm_mark m; struct xfrm_mark m;
u32 mark = xfrm_mark_get(attrs, &m); u32 mark = xfrm_mark_get(attrs, &m);
u32 if_id = 0;
err = copy_from_user_policy_type(&type, attrs); err = copy_from_user_policy_type(&type, attrs);
if (err) if (err)
...@@ -2118,8 +2144,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2118,8 +2144,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err) if (err)
return err; return err;
if (attrs[XFRMA_IF_ID])
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
if (p->index) 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 { else {
struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct nlattr *rt = attrs[XFRMA_SEC_CTX];
struct xfrm_sec_ctx *ctx; struct xfrm_sec_ctx *ctx;
...@@ -2136,7 +2165,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2136,7 +2165,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err) if (err)
return 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); &p->sel, ctx, 0, &err);
security_xfrm_policy_free(ctx); security_xfrm_policy_free(ctx);
} }
...@@ -2520,6 +2549,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { ...@@ -2520,6 +2549,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) },
[XFRMA_SET_MARK] = { .type = NLA_U32 }, [XFRMA_SET_MARK] = { .type = NLA_U32 },
[XFRMA_SET_MARK_MASK] = { .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] = { 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 ...@@ -2651,6 +2681,10 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct
if (err) if (err)
return err; return err;
err = xfrm_if_id_put(skb, x->if_id);
if (err)
return err;
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
return 0; return 0;
} }
...@@ -2749,6 +2783,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x) ...@@ -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.v));
l += nla_total_size(sizeof(x->props.smark.m)); 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. */ /* Must count x->lastused as it may become non-zero behind our back. */
l += nla_total_size_64bit(sizeof(u64)); l += nla_total_size_64bit(sizeof(u64));
...@@ -2878,6 +2914,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, ...@@ -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); err = copy_to_user_policy_type(xp->type, skb);
if (!err) if (!err)
err = xfrm_mark_put(skb, &xp->mark); err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
if (err) { if (err) {
nlmsg_cancel(skb, nlh); nlmsg_cancel(skb, nlh);
return err; return err;
...@@ -2994,6 +3032,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, ...@@ -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); err = copy_to_user_policy_type(xp->type, skb);
if (!err) if (!err)
err = xfrm_mark_put(skb, &xp->mark); err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
if (err) { if (err) {
nlmsg_cancel(skb, nlh); nlmsg_cancel(skb, nlh);
return err; return err;
...@@ -3075,6 +3115,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e ...@@ -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); err = copy_to_user_policy_type(xp->type, skb);
if (!err) if (!err)
err = xfrm_mark_put(skb, &xp->mark); err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
if (err) if (err)
goto out_free_skb; goto out_free_skb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment