aboutsummaryrefslogtreecommitdiffstats
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.c288
1 files changed, 281 insertions, 7 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 97509011c274..5ce8558eac91 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -277,6 +277,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
277 struct xfrm_usersa_info *p = NLMSG_DATA(nlh); 277 struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
278 struct xfrm_state *x; 278 struct xfrm_state *x;
279 int err; 279 int err;
280 struct km_event c;
280 281
281 err = verify_newsa_info(p, (struct rtattr **) xfrma); 282 err = verify_newsa_info(p, (struct rtattr **) xfrma);
282 if (err) 283 if (err)
@@ -286,6 +287,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
286 if (!x) 287 if (!x)
287 return err; 288 return err;
288 289
290 xfrm_state_hold(x);
289 if (nlh->nlmsg_type == XFRM_MSG_NEWSA) 291 if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
290 err = xfrm_state_add(x); 292 err = xfrm_state_add(x);
291 else 293 else
@@ -294,14 +296,24 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
294 if (err < 0) { 296 if (err < 0) {
295 x->km.state = XFRM_STATE_DEAD; 297 x->km.state = XFRM_STATE_DEAD;
296 xfrm_state_put(x); 298 xfrm_state_put(x);
299 goto out;
297 } 300 }
298 301
302 c.seq = nlh->nlmsg_seq;
303 c.pid = nlh->nlmsg_pid;
304 c.event = nlh->nlmsg_type;
305
306 km_state_notify(x, &c);
307out:
308 xfrm_state_put(x);
299 return err; 309 return err;
300} 310}
301 311
302static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 312static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
303{ 313{
304 struct xfrm_state *x; 314 struct xfrm_state *x;
315 int err;
316 struct km_event c;
305 struct xfrm_usersa_id *p = NLMSG_DATA(nlh); 317 struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
306 318
307 x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); 319 x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
@@ -313,10 +325,19 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
313 return -EPERM; 325 return -EPERM;
314 } 326 }
315 327
316 xfrm_state_delete(x); 328 err = xfrm_state_delete(x);
329 if (err < 0) {
330 xfrm_state_put(x);
331 return err;
332 }
333
334 c.seq = nlh->nlmsg_seq;
335 c.pid = nlh->nlmsg_pid;
336 c.event = nlh->nlmsg_type;
337 km_state_notify(x, &c);
317 xfrm_state_put(x); 338 xfrm_state_put(x);
318 339
319 return 0; 340 return err;
320} 341}
321 342
322static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 343static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
@@ -681,6 +702,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
681{ 702{
682 struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); 703 struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
683 struct xfrm_policy *xp; 704 struct xfrm_policy *xp;
705 struct km_event c;
684 int err; 706 int err;
685 int excl; 707 int excl;
686 708
@@ -692,6 +714,10 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
692 if (!xp) 714 if (!xp)
693 return err; 715 return err;
694 716
717 /* shouldnt excl be based on nlh flags??
718 * Aha! this is anti-netlink really i.e more pfkey derived
719 * in netlink excl is a flag and you wouldnt need
720 * a type XFRM_MSG_UPDPOLICY - JHS */
695 excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; 721 excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
696 err = xfrm_policy_insert(p->dir, xp, excl); 722 err = xfrm_policy_insert(p->dir, xp, excl);
697 if (err) { 723 if (err) {
@@ -699,6 +725,11 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
699 return err; 725 return err;
700 } 726 }
701 727
728 c.event = nlh->nlmsg_type;
729 c.seq = nlh->nlmsg_seq;
730 c.pid = nlh->nlmsg_pid;
731 km_policy_notify(xp, p->dir, &c);
732
702 xfrm_pol_put(xp); 733 xfrm_pol_put(xp);
703 734
704 return 0; 735 return 0;
@@ -816,6 +847,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
816 struct xfrm_policy *xp; 847 struct xfrm_policy *xp;
817 struct xfrm_userpolicy_id *p; 848 struct xfrm_userpolicy_id *p;
818 int err; 849 int err;
850 struct km_event c;
819 int delete; 851 int delete;
820 852
821 p = NLMSG_DATA(nlh); 853 p = NLMSG_DATA(nlh);
@@ -843,6 +875,12 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
843 NETLINK_CB(skb).pid, 875 NETLINK_CB(skb).pid,
844 MSG_DONTWAIT); 876 MSG_DONTWAIT);
845 } 877 }
878 } else {
879 c.data.byid = p->index;
880 c.event = nlh->nlmsg_type;
881 c.seq = nlh->nlmsg_seq;
882 c.pid = nlh->nlmsg_pid;
883 km_policy_notify(xp, p->dir, &c);
846 } 884 }
847 885
848 xfrm_pol_put(xp); 886 xfrm_pol_put(xp);
@@ -852,15 +890,28 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
852 890
853static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 891static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
854{ 892{
893 struct km_event c;
855 struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); 894 struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
856 895
857 xfrm_state_flush(p->proto); 896 xfrm_state_flush(p->proto);
897 c.data.proto = p->proto;
898 c.event = nlh->nlmsg_type;
899 c.seq = nlh->nlmsg_seq;
900 c.pid = nlh->nlmsg_pid;
901 km_state_notify(NULL, &c);
902
858 return 0; 903 return 0;
859} 904}
860 905
861static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 906static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
862{ 907{
908 struct km_event c;
909
863 xfrm_policy_flush(); 910 xfrm_policy_flush();
911 c.event = nlh->nlmsg_type;
912 c.seq = nlh->nlmsg_seq;
913 c.pid = nlh->nlmsg_pid;
914 km_policy_notify(NULL, 0, &c);
864 return 0; 915 return 0;
865} 916}
866 917
@@ -1069,15 +1120,16 @@ nlmsg_failure:
1069 return -1; 1120 return -1;
1070} 1121}
1071 1122
1072static int xfrm_send_state_notify(struct xfrm_state *x, int hard) 1123static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
1073{ 1124{
1074 struct sk_buff *skb; 1125 struct sk_buff *skb;
1126 int len = NLMSG_LENGTH(sizeof(struct xfrm_user_expire));
1075 1127
1076 skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC); 1128 skb = alloc_skb(len, GFP_ATOMIC);
1077 if (skb == NULL) 1129 if (skb == NULL)
1078 return -ENOMEM; 1130 return -ENOMEM;
1079 1131
1080 if (build_expire(skb, x, hard) < 0) 1132 if (build_expire(skb, x, c->data.hard) < 0)
1081 BUG(); 1133 BUG();
1082 1134
1083 NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE; 1135 NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1085,6 +1137,131 @@ static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
1085 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); 1137 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
1086} 1138}
1087 1139
1140static int xfrm_notify_sa_flush(struct km_event *c)
1141{
1142 struct xfrm_usersa_flush *p;
1143 struct nlmsghdr *nlh;
1144 struct sk_buff *skb;
1145 unsigned char *b;
1146 int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
1147
1148 skb = alloc_skb(len, GFP_ATOMIC);
1149 if (skb == NULL)
1150 return -ENOMEM;
1151 b = skb->tail;
1152
1153 nlh = NLMSG_PUT(skb, c->pid, c->seq,
1154 XFRM_MSG_FLUSHSA, sizeof(*p));
1155 nlh->nlmsg_flags = 0;
1156
1157 p = NLMSG_DATA(nlh);
1158 p->proto = c->data.proto;
1159
1160 nlh->nlmsg_len = skb->tail - b;
1161
1162 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
1163
1164nlmsg_failure:
1165 kfree_skb(skb);
1166 return -1;
1167}
1168
1169static int inline xfrm_sa_len(struct xfrm_state *x)
1170{
1171 int l = 0;
1172 if (x->aalg)
1173 l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8);
1174 if (x->ealg)
1175 l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8);
1176 if (x->calg)
1177 l += RTA_SPACE(sizeof(*x->calg));
1178 if (x->encap)
1179 l += RTA_SPACE(sizeof(*x->encap));
1180
1181 return l;
1182}
1183
1184static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
1185{
1186 struct xfrm_usersa_info *p;
1187 struct xfrm_usersa_id *id;
1188 struct nlmsghdr *nlh;
1189 struct sk_buff *skb;
1190 unsigned char *b;
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);
1200
1201 skb = alloc_skb(len, GFP_ATOMIC);
1202 if (skb == NULL)
1203 return -ENOMEM;
1204 b = skb->tail;
1205
1206 nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen);
1207 nlh->nlmsg_flags = 0;
1208
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
1220 copy_to_user_state(x, p);
1221
1222 if (x->aalg)
1223 RTA_PUT(skb, XFRMA_ALG_AUTH,
1224 sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg);
1225 if (x->ealg)
1226 RTA_PUT(skb, XFRMA_ALG_CRYPT,
1227 sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg);
1228 if (x->calg)
1229 RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
1230
1231 if (x->encap)
1232 RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
1233
1234 nlh->nlmsg_len = skb->tail - b;
1235
1236 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
1237
1238nlmsg_failure:
1239rtattr_failure:
1240 kfree_skb(skb);
1241 return -1;
1242}
1243
1244static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
1245{
1246
1247 switch (c->event) {
1248 case XFRM_MSG_EXPIRE:
1249 return xfrm_exp_state_notify(x, c);
1250 case XFRM_MSG_DELSA:
1251 case XFRM_MSG_UPDSA:
1252 case XFRM_MSG_NEWSA:
1253 return xfrm_notify_sa(x, c);
1254 case XFRM_MSG_FLUSHSA:
1255 return xfrm_notify_sa_flush(c);
1256 default:
1257 printk("xfrm_user: Unknown SA event %d\n", c->event);
1258 break;
1259 }
1260
1261 return 0;
1262
1263}
1264
1088static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, 1265static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
1089 struct xfrm_tmpl *xt, struct xfrm_policy *xp, 1266 struct xfrm_tmpl *xt, struct xfrm_policy *xp,
1090 int dir) 1267 int dir)
@@ -1218,7 +1395,7 @@ nlmsg_failure:
1218 return -1; 1395 return -1;
1219} 1396}
1220 1397
1221static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard) 1398static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
1222{ 1399{
1223 struct sk_buff *skb; 1400 struct sk_buff *skb;
1224 size_t len; 1401 size_t len;
@@ -1229,7 +1406,7 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
1229 if (skb == NULL) 1406 if (skb == NULL)
1230 return -ENOMEM; 1407 return -ENOMEM;
1231 1408
1232 if (build_polexpire(skb, xp, dir, hard) < 0) 1409 if (build_polexpire(skb, xp, dir, c->data.hard) < 0)
1233 BUG(); 1410 BUG();
1234 1411
1235 NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE; 1412 NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1237,6 +1414,103 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
1237 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); 1414 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
1238} 1415}
1239 1416
1417static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
1418{
1419 struct xfrm_userpolicy_info *p;
1420 struct xfrm_userpolicy_id *id;
1421 struct nlmsghdr *nlh;
1422 struct sk_buff *skb;
1423 unsigned char *b;
1424 int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
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);
1433
1434 skb = alloc_skb(len, GFP_ATOMIC);
1435 if (skb == NULL)
1436 return -ENOMEM;
1437 b = skb->tail;
1438
1439 nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen);
1440
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 }
1453
1454 nlh->nlmsg_flags = 0;
1455
1456 copy_to_user_policy(xp, p, dir);
1457 if (copy_to_user_tmpl(xp, skb) < 0)
1458 goto nlmsg_failure;
1459
1460 nlh->nlmsg_len = skb->tail - b;
1461
1462 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
1463
1464nlmsg_failure:
1465rtattr_failure:
1466 kfree_skb(skb);
1467 return -1;
1468}
1469
1470static int xfrm_notify_policy_flush(struct km_event *c)
1471{
1472 struct nlmsghdr *nlh;
1473 struct sk_buff *skb;
1474 unsigned char *b;
1475 int len = NLMSG_LENGTH(0);
1476
1477 skb = alloc_skb(len, GFP_ATOMIC);
1478 if (skb == NULL)
1479 return -ENOMEM;
1480 b = skb->tail;
1481
1482
1483 nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
1484
1485 nlh->nlmsg_len = skb->tail - b;
1486
1487 return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
1488
1489nlmsg_failure:
1490 kfree_skb(skb);
1491 return -1;
1492}
1493
1494static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
1495{
1496
1497 switch (c->event) {
1498 case XFRM_MSG_NEWPOLICY:
1499 case XFRM_MSG_UPDPOLICY:
1500 case XFRM_MSG_DELPOLICY:
1501 return xfrm_notify_policy(xp, dir, c);
1502 case XFRM_MSG_FLUSHPOLICY:
1503 return xfrm_notify_policy_flush(c);
1504 case XFRM_MSG_POLEXPIRE:
1505 return xfrm_exp_policy_notify(xp, dir, c);
1506 default:
1507 printk("xfrm_user: Unknown Policy event %d\n", c->event);
1508 }
1509
1510 return 0;
1511
1512}
1513
1240static struct xfrm_mgr netlink_mgr = { 1514static struct xfrm_mgr netlink_mgr = {
1241 .id = "netlink", 1515 .id = "netlink",
1242 .notify = xfrm_send_state_notify, 1516 .notify = xfrm_send_state_notify,