Skip to content

Commit

Permalink
xfrm: Allow user space config of SAD mark
Browse files Browse the repository at this point in the history
Add ability for netlink userspace to manipulate the SAD
and manipulate the mark, retrieve it and get events with a defined
mark.
MIGRATE may be added later.

Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jamal Hadi Salim authored and David S. Miller committed Feb 23, 2010
1 parent 34f8d88 commit 6f26b61
Showing 1 changed file with 57 additions and 15 deletions.
72 changes: 57 additions & 15 deletions net/xfrm/xfrm_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#endif

#define DUMMY_MARK 0
static struct xfrm_mark dummy_mark = {0, 0};

static inline int aead_len(struct xfrm_algo_aead *alg)
{
Expand Down Expand Up @@ -449,6 +448,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
goto error;
}

xfrm_mark_get(attrs, &x->mark);

err = xfrm_init_state(x);
if (err)
goto error;
Expand Down Expand Up @@ -529,11 +530,13 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
int *errp)
{
struct xfrm_state *x = NULL;
struct xfrm_mark m;
int err;
u32 mark = xfrm_mark_get(attrs, &m);

if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
err = -ESRCH;
x = xfrm_state_lookup(net, DUMMY_MARK, &p->daddr, p->spi, p->proto, p->family);
x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family);
} else {
xfrm_address_t *saddr = NULL;

Expand All @@ -544,7 +547,8 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
}

err = -ESRCH;
x = xfrm_state_lookup_byaddr(net, DUMMY_MARK, &p->daddr, saddr,
x = xfrm_state_lookup_byaddr(net, mark,
&p->daddr, saddr,
p->proto, p->family);
}

Expand Down Expand Up @@ -686,6 +690,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
if (x->encap)
NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);

if (xfrm_mark_put(skb, &x->mark))
goto nla_put_failure;

if (x->security && copy_sec_ctx(x->security, skb) < 0)
goto nla_put_failure;

Expand Down Expand Up @@ -950,6 +957,8 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
xfrm_address_t *daddr;
int family;
int err;
u32 mark;
struct xfrm_mark m;

p = nlmsg_data(nlh);
err = verify_userspi_info(p);
Expand All @@ -960,16 +969,18 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
daddr = &p->info.id.daddr;

x = NULL;

mark = xfrm_mark_get(attrs, &m);
if (p->info.seq) {
x = xfrm_find_acq_byseq(net, DUMMY_MARK, p->info.seq);
x = xfrm_find_acq_byseq(net, mark, p->info.seq);
if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {
xfrm_state_put(x);
x = NULL;
}
}

if (!x)
x = xfrm_find_acq(net, &dummy_mark, p->info.mode, p->info.reqid,
x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
p->info.id.proto, daddr,
&p->info.saddr, 1,
family);
Expand Down Expand Up @@ -1474,8 +1485,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err)
return err;
}
xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir,
&p->sel, ctx, delete, &err);
xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir, &p->sel,
ctx, delete, &err);
security_xfrm_policy_free(ctx);
}
if (xp == NULL)
Expand Down Expand Up @@ -1547,6 +1558,7 @@ static inline size_t xfrm_aevent_msgsize(void)
return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id))
+ nla_total_size(sizeof(struct xfrm_replay_state))
+ nla_total_size(sizeof(struct xfrm_lifetime_cur))
+ nla_total_size(sizeof(struct xfrm_mark))
+ nla_total_size(4) /* XFRM_AE_RTHR */
+ nla_total_size(4); /* XFRM_AE_ETHR */
}
Expand Down Expand Up @@ -1579,6 +1591,9 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve
NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH,
x->replay_maxage * 10 / HZ);

if (xfrm_mark_put(skb, &x->mark))
goto nla_put_failure;

return nlmsg_end(skb, nlh);

nla_put_failure:
Expand All @@ -1594,14 +1609,18 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct sk_buff *r_skb;
int err;
struct km_event c;
u32 mark;
struct xfrm_mark m;
struct xfrm_aevent_id *p = nlmsg_data(nlh);
struct xfrm_usersa_id *id = &p->sa_id;

r_skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC);
if (r_skb == NULL)
return -ENOMEM;

x = xfrm_state_lookup(net, DUMMY_MARK, &id->daddr, id->spi, id->proto, id->family);
mark = xfrm_mark_get(attrs, &m);

x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family);
if (x == NULL) {
kfree_skb(r_skb);
return -ESRCH;
Expand Down Expand Up @@ -1632,6 +1651,8 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct xfrm_state *x;
struct km_event c;
int err = - EINVAL;
u32 mark = 0;
struct xfrm_mark m;
struct xfrm_aevent_id *p = nlmsg_data(nlh);
struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
Expand All @@ -1643,7 +1664,9 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
return err;

x = xfrm_state_lookup(net, DUMMY_MARK, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
mark = xfrm_mark_get(attrs, &m);

x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
if (x == NULL)
return -ESRCH;

Expand Down Expand Up @@ -1729,7 +1752,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err)
return err;
}
xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir, &p->sel, ctx, 0, &err);
xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir,
&p->sel, ctx, 0, &err);
security_xfrm_policy_free(ctx);
}
if (xp == NULL)
Expand Down Expand Up @@ -1769,8 +1793,10 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
int err;
struct xfrm_user_expire *ue = nlmsg_data(nlh);
struct xfrm_usersa_info *p = &ue->state;
struct xfrm_mark m;
u32 mark = xfrm_mark_get(attrs, &m);;

x = xfrm_state_lookup(net, DUMMY_MARK, &p->id.daddr, p->id.spi, p->id.proto, p->family);
x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family);

err = -ENOENT;
if (x == NULL)
Expand Down Expand Up @@ -1804,6 +1830,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
struct xfrm_user_tmpl *ut;
int i;
struct nlattr *rt = attrs[XFRMA_TMPL];
struct xfrm_mark mark;

struct xfrm_user_acquire *ua = nlmsg_data(nlh);
struct xfrm_state *x = xfrm_state_alloc(net);
Expand All @@ -1812,6 +1839,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!x)
goto nomem;

xfrm_mark_get(attrs, &mark);

err = verify_newpolicy_info(&ua->policy);
if (err)
goto bad_policy;
Expand All @@ -1824,7 +1853,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
memcpy(&x->id, &ua->id, sizeof(ua->id));
memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr));
memcpy(&x->sel, &ua->sel, sizeof(ua->sel));

xp->mark.m = x->mark.m = mark.m;
xp->mark.v = x->mark.v = mark.v;
ut = nla_data(rt);
/* extract the templates and for each call km_key */
for (i = 0; i < xp->xfrm_nr; i++, ut++) {
Expand Down Expand Up @@ -2084,6 +2114,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)},
[XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) },
[XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) },
[XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) },
};

static struct xfrm_link {
Expand Down Expand Up @@ -2163,7 +2194,8 @@ static void xfrm_netlink_rcv(struct sk_buff *skb)

static inline size_t xfrm_expire_msgsize(void)
{
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire));
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
+ nla_total_size(sizeof(struct xfrm_mark));
}

static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
Expand All @@ -2179,7 +2211,13 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve
copy_to_user_state(x, &ue->state);
ue->hard = (c->data.hard != 0) ? 1 : 0;

if (xfrm_mark_put(skb, &x->mark))
goto nla_put_failure;

return nlmsg_end(skb, nlh);

nla_put_failure:
return -EMSGSIZE;
}

static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
Expand All @@ -2191,8 +2229,10 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
if (skb == NULL)
return -ENOMEM;

if (build_expire(skb, x, c) < 0)
BUG();
if (build_expire(skb, x, c) < 0) {
kfree_skb(skb);
return -EMSGSIZE;
}

return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
}
Expand Down Expand Up @@ -2280,6 +2320,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
if (c->event == XFRM_MSG_DELSA) {
len += nla_total_size(headlen);
headlen = sizeof(*id);
len += nla_total_size(sizeof(struct xfrm_mark));
}
len += NLMSG_ALIGN(headlen);

Expand Down Expand Up @@ -2350,6 +2391,7 @@ static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x,
{
return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))
+ nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
+ nla_total_size(sizeof(struct xfrm_mark))
+ nla_total_size(xfrm_user_sec_ctx_size(x->security))
+ userpolicy_type_attrsize();
}
Expand Down

0 comments on commit 6f26b61

Please sign in to comment.