aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/xfrm.h2
-rw-r--r--net/xfrm/xfrm_user.c47
2 files changed, 45 insertions, 4 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 03bc600516ea..d68391a9b9f3 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -174,6 +174,8 @@ enum xfrm_attr_type_t {
174 XFRMA_ALG_COMP, /* struct xfrm_algo */ 174 XFRMA_ALG_COMP, /* struct xfrm_algo */
175 XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */ 175 XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */
176 XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */ 176 XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */
177 XFRMA_SA,
178 XFRMA_POLICY,
177 __XFRMA_MAX 179 __XFRMA_MAX
178 180
179#define XFRMA_MAX (__XFRMA_MAX - 1) 181#define XFRMA_MAX (__XFRMA_MAX - 1)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index ffe1b217347c..5ce8558eac91 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1168,7 +1168,7 @@ nlmsg_failure:
1168 1168
1169static int inline xfrm_sa_len(struct xfrm_state *x) 1169static int inline xfrm_sa_len(struct xfrm_state *x)
1170{ 1170{
1171 int l = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); 1171 int l = 0;
1172 if (x->aalg) 1172 if (x->aalg)
1173 l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8); 1173 l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8);
1174 if (x->ealg) 1174 if (x->ealg)
@@ -1184,20 +1184,39 @@ static int inline xfrm_sa_len(struct xfrm_state *x)
1184static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) 1184static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
1185{ 1185{
1186 struct xfrm_usersa_info *p; 1186 struct xfrm_usersa_info *p;
1187 struct xfrm_usersa_id *id;
1187 struct nlmsghdr *nlh; 1188 struct nlmsghdr *nlh;
1188 struct sk_buff *skb; 1189 struct sk_buff *skb;
1189 unsigned char *b; 1190 unsigned char *b;
1190 int len = xfrm_sa_len(x); 1191 int len = xfrm_sa_len(x);
1192 int headlen;
1193
1194 headlen = sizeof(*p);
1195 if (c->event == XFRM_MSG_DELSA) {
1196 len += RTA_SPACE(headlen);
1197 headlen = sizeof(*id);
1198 }
1199 len += NLMSG_SPACE(headlen);
1191 1200
1192 skb = alloc_skb(len, GFP_ATOMIC); 1201 skb = alloc_skb(len, GFP_ATOMIC);
1193 if (skb == NULL) 1202 if (skb == NULL)
1194 return -ENOMEM; 1203 return -ENOMEM;
1195 b = skb->tail; 1204 b = skb->tail;
1196 1205
1197 nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, sizeof(*p)); 1206 nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen);
1198 nlh->nlmsg_flags = 0; 1207 nlh->nlmsg_flags = 0;
1199 1208
1200 p = NLMSG_DATA(nlh); 1209 p = NLMSG_DATA(nlh);
1210 if (c->event == XFRM_MSG_DELSA) {
1211 id = NLMSG_DATA(nlh);
1212 memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
1213 id->spi = x->id.spi;
1214 id->family = x->props.family;
1215 id->proto = x->id.proto;
1216
1217 p = RTA_DATA(__RTA_PUT(skb, XFRMA_SA, sizeof(*p)));
1218 }
1219
1201 copy_to_user_state(x, p); 1220 copy_to_user_state(x, p);
1202 1221
1203 if (x->aalg) 1222 if (x->aalg)
@@ -1398,20 +1417,39 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve
1398static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) 1417static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
1399{ 1418{
1400 struct xfrm_userpolicy_info *p; 1419 struct xfrm_userpolicy_info *p;
1420 struct xfrm_userpolicy_id *id;
1401 struct nlmsghdr *nlh; 1421 struct nlmsghdr *nlh;
1402 struct sk_buff *skb; 1422 struct sk_buff *skb;
1403 unsigned char *b; 1423 unsigned char *b;
1404 int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 1424 int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
1405 len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_info)); 1425 int headlen;
1426
1427 headlen = sizeof(*p);
1428 if (c->event == XFRM_MSG_DELPOLICY) {
1429 len += RTA_SPACE(headlen);
1430 headlen = sizeof(*id);
1431 }
1432 len += NLMSG_SPACE(headlen);
1406 1433
1407 skb = alloc_skb(len, GFP_ATOMIC); 1434 skb = alloc_skb(len, GFP_ATOMIC);
1408 if (skb == NULL) 1435 if (skb == NULL)
1409 return -ENOMEM; 1436 return -ENOMEM;
1410 b = skb->tail; 1437 b = skb->tail;
1411 1438
1412 nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, sizeof(*p)); 1439 nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen);
1413 1440
1414 p = NLMSG_DATA(nlh); 1441 p = NLMSG_DATA(nlh);
1442 if (c->event == XFRM_MSG_DELPOLICY) {
1443 id = NLMSG_DATA(nlh);
1444 memset(id, 0, sizeof(*id));
1445 id->dir = dir;
1446 if (c->data.byid)
1447 id->index = xp->index;
1448 else
1449 memcpy(&id->sel, &xp->selector, sizeof(id->sel));
1450
1451 p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p)));
1452 }
1415 1453
1416 nlh->nlmsg_flags = 0; 1454 nlh->nlmsg_flags = 0;
1417 1455
@@ -1424,6 +1462,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *
1424 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC); 1462 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
1425 1463
1426nlmsg_failure: 1464nlmsg_failure:
1465rtattr_failure:
1427 kfree_skb(skb); 1466 kfree_skb(skb);
1428 return -1; 1467 return -1;
1429} 1468}