summaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r--net/xfrm/xfrm_user.c186
1 files changed, 110 insertions, 76 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index e81e2fb3d42..69110fed64b 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -71,7 +71,7 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
default:
return -EINVAL;
- };
+ }
algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
return 0;
@@ -152,7 +152,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
default:
goto out;
- };
+ }
err = -EINVAL;
switch (p->id.proto) {
@@ -192,7 +192,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
default:
goto out;
- };
+ }
if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH)))
goto out;
@@ -217,7 +217,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
default:
goto out;
- };
+ }
err = 0;
@@ -272,9 +272,8 @@ static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_a
}
-static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp)
+static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
{
- struct xfrm_sec_ctx *xfrm_ctx = xp->security;
int len = 0;
if (xfrm_ctx) {
@@ -577,7 +576,7 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
struct sk_buff *skb = sp->out_skb;
struct xfrm_usersa_info *p;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
if (sp->this_idx < sp->start_idx)
goto out;
@@ -622,14 +621,14 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
if (x->lastused)
RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused);
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
out:
sp->this_idx++;
return 0;
nlmsg_failure:
rtattr_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -673,6 +672,61 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
return skb;
}
+static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
+{
+ struct xfrm_sadinfo si;
+ struct nlmsghdr *nlh;
+ u32 *f;
+
+ nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
+ if (nlh == NULL) /* shouldnt really happen ... */
+ return -EMSGSIZE;
+
+ f = nlmsg_data(nlh);
+ *f = flags;
+ xfrm_sad_getinfo(&si);
+
+ if (flags & XFRM_SAD_HMASK)
+ NLA_PUT_U32(skb, XFRMA_SADHMASK, si.sadhcnt);
+ if (flags & XFRM_SAD_HMAX)
+ NLA_PUT_U32(skb, XFRMA_SADHMAX, si.sadhmcnt);
+ if (flags & XFRM_SAD_CNT)
+ NLA_PUT_U32(skb, XFRMA_SADCNT, si.sadcnt);
+
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
+{
+ struct sk_buff *r_skb;
+ u32 *flags = NLMSG_DATA(nlh);
+ u32 spid = NETLINK_CB(skb).pid;
+ u32 seq = nlh->nlmsg_seq;
+ int len = NLMSG_LENGTH(sizeof(u32));
+
+ if (*flags & XFRM_SAD_HMASK)
+ len += RTA_SPACE(sizeof(u32));
+ if (*flags & XFRM_SAD_HMAX)
+ len += RTA_SPACE(sizeof(u32));
+ if (*flags & XFRM_SAD_CNT)
+ len += RTA_SPACE(sizeof(u32));
+
+ r_skb = alloc_skb(len, GFP_ATOMIC);
+
+ if (r_skb == NULL)
+ return -ENOMEM;
+
+ if (build_sadinfo(r_skb, spid, seq, *flags) < 0)
+ BUG();
+
+ return nlmsg_unicast(xfrm_nl, r_skb, spid);
+}
+
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct rtattr **xfrma)
{
@@ -712,7 +766,7 @@ static int verify_userspi_info(struct xfrm_userspi_info *p)
default:
return -EINVAL;
- };
+ }
if (p->min > p->max)
return -EINVAL;
@@ -790,7 +844,7 @@ static int verify_policy_dir(u8 dir)
default:
return -EINVAL;
- };
+ }
return 0;
}
@@ -806,7 +860,7 @@ static int verify_policy_type(u8 type)
default:
return -EINVAL;
- };
+ }
return 0;
}
@@ -822,7 +876,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
default:
return -EINVAL;
- };
+ }
switch (p->action) {
case XFRM_POLICY_ALLOW:
@@ -831,7 +885,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
default:
return -EINVAL;
- };
+ }
switch (p->sel.family) {
case AF_INET:
@@ -846,7 +900,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
default:
return -EINVAL;
- };
+ }
return verify_policy_dir(p->dir);
}
@@ -913,7 +967,7 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
#endif
default:
return -EINVAL;
- };
+ }
}
return 0;
@@ -1158,7 +1212,7 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
struct sk_buff *in_skb = sp->in_skb;
struct sk_buff *skb = sp->out_skb;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
if (sp->this_idx < sp->start_idx)
goto out;
@@ -1177,13 +1231,13 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
if (copy_to_user_policy_type(xp->type, skb) < 0)
goto nlmsg_failure;
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
out:
sp->this_idx++;
return 0;
nlmsg_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -1331,7 +1385,7 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve
struct xfrm_aevent_id *id;
struct nlmsghdr *nlh;
struct xfrm_lifetime_cur ltime;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id));
id = NLMSG_DATA(nlh);
@@ -1363,12 +1417,12 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve
RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer);
}
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
return skb->len;
rtattr_failure:
nlmsg_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -1745,7 +1799,7 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
struct xfrm_migrate *mp;
struct xfrm_userpolicy_id *pol_id;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
int i;
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id));
@@ -1765,10 +1819,10 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
goto nlmsg_failure;
}
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
return skb->len;
nlmsg_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -1824,6 +1878,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
+ [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
};
#undef XMSGSIZE
@@ -1851,55 +1906,39 @@ static struct xfrm_link {
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae },
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
+ [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
};
-static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct rtattr *xfrma[XFRMA_MAX];
struct xfrm_link *link;
int type, min_len;
- if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
- return 0;
-
type = nlh->nlmsg_type;
-
- /* A control message: ignore them */
- if (type < XFRM_MSG_BASE)
- return 0;
-
- /* Unknown message: reply with EINVAL */
if (type > XFRM_MSG_MAX)
- goto err_einval;
+ return -EINVAL;
type -= XFRM_MSG_BASE;
link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */
- if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
- *errp = -EPERM;
- return -1;
- }
+ if (security_netlink_recv(skb, CAP_NET_ADMIN))
+ return -EPERM;
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
(nlh->nlmsg_flags & NLM_F_DUMP)) {
if (link->dump == NULL)
- goto err_einval;
-
- if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,
- link->dump, NULL)) != 0) {
- return -1;
- }
+ return -EINVAL;
- netlink_queue_skip(nlh, skb);
- return -1;
+ return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);
}
memset(xfrma, 0, sizeof(xfrma));
if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))
- goto err_einval;
+ return -EINVAL;
if (nlh->nlmsg_len > min_len) {
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
@@ -1909,7 +1948,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
unsigned short flavor = attr->rta_type;
if (flavor) {
if (flavor > XFRMA_MAX)
- goto err_einval;
+ return -EINVAL;
xfrma[flavor - 1] = attr;
}
attr = RTA_NEXT(attr, attrlen);
@@ -1917,14 +1956,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
}
if (link->doit == NULL)
- goto err_einval;
- *errp = link->doit(skb, nlh, xfrma);
-
- return *errp;
+ return -EINVAL;
-err_einval:
- *errp = -EINVAL;
- return -1;
+ return link->doit(skb, nlh, xfrma);
}
static void xfrm_netlink_rcv(struct sock *sk, int len)
@@ -1943,7 +1977,7 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve
{
struct xfrm_user_expire *ue;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE,
sizeof(*ue));
@@ -1953,11 +1987,11 @@ 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;
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
return skb->len;
nlmsg_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -2000,7 +2034,7 @@ static int xfrm_notify_sa_flush(struct km_event *c)
struct xfrm_usersa_flush *p;
struct nlmsghdr *nlh;
struct sk_buff *skb;
- unsigned char *b;
+ sk_buff_data_t b;
int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
skb = alloc_skb(len, GFP_ATOMIC);
@@ -2046,7 +2080,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
struct xfrm_usersa_id *id;
struct nlmsghdr *nlh;
struct sk_buff *skb;
- unsigned char *b;
+ sk_buff_data_t b;
int len = xfrm_sa_len(x);
int headlen;
@@ -2130,7 +2164,7 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
{
struct xfrm_user_acquire *ua;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
__u32 seq = xfrm_get_acqseq();
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE,
@@ -2154,11 +2188,11 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
if (copy_to_user_policy_type(xp->type, skb) < 0)
goto nlmsg_failure;
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
return skb->len;
nlmsg_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -2170,7 +2204,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire));
- len += RTA_SPACE(xfrm_user_sec_ctx_size(xp));
+ len += RTA_SPACE(xfrm_user_sec_ctx_size(x->security));
#ifdef CONFIG_XFRM_SUB_POLICY
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
#endif
@@ -2250,7 +2284,7 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
struct xfrm_user_polexpire *upe;
struct nlmsghdr *nlh;
int hard = c->data.hard;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
upe = NLMSG_DATA(nlh);
@@ -2265,11 +2299,11 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
goto nlmsg_failure;
upe->hard = !!hard;
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
return skb->len;
nlmsg_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -2280,7 +2314,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve
len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire));
- len += RTA_SPACE(xfrm_user_sec_ctx_size(xp));
+ len += RTA_SPACE(xfrm_user_sec_ctx_size(xp->security));
#ifdef CONFIG_XFRM_SUB_POLICY
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
#endif
@@ -2301,7 +2335,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *
struct xfrm_userpolicy_id *id;
struct nlmsghdr *nlh;
struct sk_buff *skb;
- unsigned char *b;
+ sk_buff_data_t b;
int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
int headlen;
@@ -2358,7 +2392,7 @@ static int xfrm_notify_policy_flush(struct km_event *c)
{
struct nlmsghdr *nlh;
struct sk_buff *skb;
- unsigned char *b;
+ sk_buff_data_t b;
int len = 0;
#ifdef CONFIG_XFRM_SUB_POLICY
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
@@ -2411,7 +2445,7 @@ static int build_report(struct sk_buff *skb, u8 proto,
{
struct xfrm_user_report *ur;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ unsigned char *b = skb_tail_pointer(skb);
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur));
ur = NLMSG_DATA(nlh);
@@ -2423,12 +2457,12 @@ static int build_report(struct sk_buff *skb, u8 proto,
if (addr)
RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
- nlh->nlmsg_len = skb->tail - b;
+ nlh->nlmsg_len = skb_tail_pointer(skb) - b;
return skb->len;
nlmsg_failure:
rtattr_failure:
- skb_trim(skb, b - skb->data);
+ nlmsg_trim(skb, b);
return -1;
}
@@ -2467,7 +2501,7 @@ static int __init xfrm_user_init(void)
printk(KERN_INFO "Initializing XFRM netlink socket\n");
nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
- xfrm_netlink_rcv, THIS_MODULE);
+ xfrm_netlink_rcv, NULL, THIS_MODULE);
if (nlsk == NULL)
return -ENOMEM;
rcu_assign_pointer(xfrm_nl, nlsk);