diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 397 |
1 files changed, 378 insertions, 19 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7de17559249a..81d1005830f4 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -28,8 +28,6 @@ | |||
28 | #include <net/netlink.h> | 28 | #include <net/netlink.h> |
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | 30 | ||
31 | static struct sock *xfrm_nl; | ||
32 | |||
33 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 31 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
34 | { | 32 | { |
35 | struct rtattr *rt = xfrma[type - 1]; | 33 | struct rtattr *rt = xfrma[type - 1]; |
@@ -103,9 +101,6 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma) | |||
103 | 101 | ||
104 | uctx = RTA_DATA(rt); | 102 | uctx = RTA_DATA(rt); |
105 | 103 | ||
106 | if (uctx->ctx_len > PAGE_SIZE) | ||
107 | return -EINVAL; | ||
108 | |||
109 | len += sizeof(struct xfrm_user_sec_ctx); | 104 | len += sizeof(struct xfrm_user_sec_ctx); |
110 | len += uctx->ctx_len; | 105 | len += uctx->ctx_len; |
111 | 106 | ||
@@ -276,6 +271,56 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * | |||
276 | x->props.flags = p->flags; | 271 | x->props.flags = p->flags; |
277 | } | 272 | } |
278 | 273 | ||
274 | /* | ||
275 | * someday when pfkey also has support, we could have the code | ||
276 | * somehow made shareable and move it to xfrm_state.c - JHS | ||
277 | * | ||
278 | */ | ||
279 | static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) | ||
280 | { | ||
281 | int err = - EINVAL; | ||
282 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | ||
283 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | ||
284 | struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; | ||
285 | struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; | ||
286 | |||
287 | if (rp) { | ||
288 | struct xfrm_replay_state *replay; | ||
289 | if (RTA_PAYLOAD(rp) < sizeof(*replay)) | ||
290 | goto error; | ||
291 | replay = RTA_DATA(rp); | ||
292 | memcpy(&x->replay, replay, sizeof(*replay)); | ||
293 | memcpy(&x->preplay, replay, sizeof(*replay)); | ||
294 | } | ||
295 | |||
296 | if (lt) { | ||
297 | struct xfrm_lifetime_cur *ltime; | ||
298 | if (RTA_PAYLOAD(lt) < sizeof(*ltime)) | ||
299 | goto error; | ||
300 | ltime = RTA_DATA(lt); | ||
301 | x->curlft.bytes = ltime->bytes; | ||
302 | x->curlft.packets = ltime->packets; | ||
303 | x->curlft.add_time = ltime->add_time; | ||
304 | x->curlft.use_time = ltime->use_time; | ||
305 | } | ||
306 | |||
307 | if (et) { | ||
308 | if (RTA_PAYLOAD(et) < sizeof(u32)) | ||
309 | goto error; | ||
310 | x->replay_maxage = *(u32*)RTA_DATA(et); | ||
311 | } | ||
312 | |||
313 | if (rt) { | ||
314 | if (RTA_PAYLOAD(rt) < sizeof(u32)) | ||
315 | goto error; | ||
316 | x->replay_maxdiff = *(u32*)RTA_DATA(rt); | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | error: | ||
321 | return err; | ||
322 | } | ||
323 | |||
279 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | 324 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, |
280 | struct rtattr **xfrma, | 325 | struct rtattr **xfrma, |
281 | int *errp) | 326 | int *errp) |
@@ -311,6 +356,18 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
311 | goto error; | 356 | goto error; |
312 | 357 | ||
313 | x->km.seq = p->seq; | 358 | x->km.seq = p->seq; |
359 | x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; | ||
360 | /* sysctl_xfrm_aevent_etime is in 100ms units */ | ||
361 | x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; | ||
362 | x->preplay.bitmap = 0; | ||
363 | x->preplay.seq = x->replay.seq+x->replay_maxdiff; | ||
364 | x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; | ||
365 | |||
366 | /* override default values from above */ | ||
367 | |||
368 | err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); | ||
369 | if (err < 0) | ||
370 | goto error; | ||
314 | 371 | ||
315 | return x; | 372 | return x; |
316 | 373 | ||
@@ -1025,9 +1082,142 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma | |||
1025 | return 0; | 1082 | return 0; |
1026 | } | 1083 | } |
1027 | 1084 | ||
1028 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1085 | |
1086 | static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | ||
1087 | { | ||
1088 | struct xfrm_aevent_id *id; | ||
1089 | struct nlmsghdr *nlh; | ||
1090 | struct xfrm_lifetime_cur ltime; | ||
1091 | unsigned char *b = skb->tail; | ||
1092 | |||
1093 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); | ||
1094 | id = NLMSG_DATA(nlh); | ||
1095 | nlh->nlmsg_flags = 0; | ||
1096 | |||
1097 | id->sa_id.daddr = x->id.daddr; | ||
1098 | id->sa_id.spi = x->id.spi; | ||
1099 | id->sa_id.family = x->props.family; | ||
1100 | id->sa_id.proto = x->id.proto; | ||
1101 | id->flags = c->data.aevent; | ||
1102 | |||
1103 | RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); | ||
1104 | |||
1105 | ltime.bytes = x->curlft.bytes; | ||
1106 | ltime.packets = x->curlft.packets; | ||
1107 | ltime.add_time = x->curlft.add_time; | ||
1108 | ltime.use_time = x->curlft.use_time; | ||
1109 | |||
1110 | RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); | ||
1111 | |||
1112 | if (id->flags&XFRM_AE_RTHR) { | ||
1113 | RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); | ||
1114 | } | ||
1115 | |||
1116 | if (id->flags&XFRM_AE_ETHR) { | ||
1117 | u32 etimer = x->replay_maxage*10/HZ; | ||
1118 | RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); | ||
1119 | } | ||
1120 | |||
1121 | nlh->nlmsg_len = skb->tail - b; | ||
1122 | return skb->len; | ||
1123 | |||
1124 | rtattr_failure: | ||
1125 | nlmsg_failure: | ||
1126 | skb_trim(skb, b - skb->data); | ||
1127 | return -1; | ||
1128 | } | ||
1129 | |||
1130 | static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1131 | { | ||
1132 | struct xfrm_state *x; | ||
1133 | struct sk_buff *r_skb; | ||
1134 | int err; | ||
1135 | struct km_event c; | ||
1136 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | ||
1137 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | ||
1138 | struct xfrm_usersa_id *id = &p->sa_id; | ||
1139 | |||
1140 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | ||
1141 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | ||
1142 | |||
1143 | if (p->flags&XFRM_AE_RTHR) | ||
1144 | len+=RTA_SPACE(sizeof(u32)); | ||
1145 | |||
1146 | if (p->flags&XFRM_AE_ETHR) | ||
1147 | len+=RTA_SPACE(sizeof(u32)); | ||
1148 | |||
1149 | r_skb = alloc_skb(len, GFP_ATOMIC); | ||
1150 | if (r_skb == NULL) | ||
1151 | return -ENOMEM; | ||
1152 | |||
1153 | x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); | ||
1154 | if (x == NULL) { | ||
1155 | kfree(r_skb); | ||
1156 | return -ESRCH; | ||
1157 | } | ||
1158 | |||
1159 | /* | ||
1160 | * XXX: is this lock really needed - none of the other | ||
1161 | * gets lock (the concern is things getting updated | ||
1162 | * while we are still reading) - jhs | ||
1163 | */ | ||
1164 | spin_lock_bh(&x->lock); | ||
1165 | c.data.aevent = p->flags; | ||
1166 | c.seq = nlh->nlmsg_seq; | ||
1167 | c.pid = nlh->nlmsg_pid; | ||
1168 | |||
1169 | if (build_aevent(r_skb, x, &c) < 0) | ||
1170 | BUG(); | ||
1171 | err = netlink_unicast(xfrm_nl, r_skb, | ||
1172 | NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1173 | spin_unlock_bh(&x->lock); | ||
1174 | xfrm_state_put(x); | ||
1175 | return err; | ||
1176 | } | ||
1177 | |||
1178 | static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1029 | { | 1179 | { |
1180 | struct xfrm_state *x; | ||
1030 | struct km_event c; | 1181 | struct km_event c; |
1182 | int err = - EINVAL; | ||
1183 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | ||
1184 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | ||
1185 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | ||
1186 | |||
1187 | if (!lt && !rp) | ||
1188 | return err; | ||
1189 | |||
1190 | /* pedantic mode - thou shalt sayeth replaceth */ | ||
1191 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | ||
1192 | return err; | ||
1193 | |||
1194 | x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | ||
1195 | if (x == NULL) | ||
1196 | return -ESRCH; | ||
1197 | |||
1198 | if (x->km.state != XFRM_STATE_VALID) | ||
1199 | goto out; | ||
1200 | |||
1201 | spin_lock_bh(&x->lock); | ||
1202 | err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); | ||
1203 | spin_unlock_bh(&x->lock); | ||
1204 | if (err < 0) | ||
1205 | goto out; | ||
1206 | |||
1207 | c.event = nlh->nlmsg_type; | ||
1208 | c.seq = nlh->nlmsg_seq; | ||
1209 | c.pid = nlh->nlmsg_pid; | ||
1210 | c.data.aevent = XFRM_AE_CU; | ||
1211 | km_state_notify(x, &c); | ||
1212 | err = 0; | ||
1213 | out: | ||
1214 | xfrm_state_put(x); | ||
1215 | return err; | ||
1216 | } | ||
1217 | |||
1218 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1219 | { | ||
1220 | struct km_event c; | ||
1031 | 1221 | ||
1032 | xfrm_policy_flush(); | 1222 | xfrm_policy_flush(); |
1033 | c.event = nlh->nlmsg_type; | 1223 | c.event = nlh->nlmsg_type; |
@@ -1037,6 +1227,139 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x | |||
1037 | return 0; | 1227 | return 0; |
1038 | } | 1228 | } |
1039 | 1229 | ||
1230 | static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1231 | { | ||
1232 | struct xfrm_policy *xp; | ||
1233 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | ||
1234 | struct xfrm_userpolicy_info *p = &up->pol; | ||
1235 | int err = -ENOENT; | ||
1236 | |||
1237 | if (p->index) | ||
1238 | xp = xfrm_policy_byid(p->dir, p->index, 0); | ||
1239 | else { | ||
1240 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | ||
1241 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | ||
1242 | struct xfrm_policy tmp; | ||
1243 | |||
1244 | err = verify_sec_ctx_len(rtattrs); | ||
1245 | if (err) | ||
1246 | return err; | ||
1247 | |||
1248 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
1249 | if (rt) { | ||
1250 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
1251 | |||
1252 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | ||
1253 | return err; | ||
1254 | } | ||
1255 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); | ||
1256 | security_xfrm_policy_free(&tmp); | ||
1257 | } | ||
1258 | |||
1259 | if (xp == NULL) | ||
1260 | return err; | ||
1261 | read_lock(&xp->lock); | ||
1262 | if (xp->dead) { | ||
1263 | read_unlock(&xp->lock); | ||
1264 | goto out; | ||
1265 | } | ||
1266 | |||
1267 | read_unlock(&xp->lock); | ||
1268 | err = 0; | ||
1269 | if (up->hard) { | ||
1270 | xfrm_policy_delete(xp, p->dir); | ||
1271 | } else { | ||
1272 | // reset the timers here? | ||
1273 | printk("Dont know what to do with soft policy expire\n"); | ||
1274 | } | ||
1275 | km_policy_expired(xp, p->dir, up->hard, current->pid); | ||
1276 | |||
1277 | out: | ||
1278 | xfrm_pol_put(xp); | ||
1279 | return err; | ||
1280 | } | ||
1281 | |||
1282 | static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1283 | { | ||
1284 | struct xfrm_state *x; | ||
1285 | int err; | ||
1286 | struct xfrm_user_expire *ue = NLMSG_DATA(nlh); | ||
1287 | struct xfrm_usersa_info *p = &ue->state; | ||
1288 | |||
1289 | x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); | ||
1290 | err = -ENOENT; | ||
1291 | |||
1292 | if (x == NULL) | ||
1293 | return err; | ||
1294 | |||
1295 | err = -EINVAL; | ||
1296 | |||
1297 | spin_lock_bh(&x->lock); | ||
1298 | if (x->km.state != XFRM_STATE_VALID) | ||
1299 | goto out; | ||
1300 | km_state_expired(x, ue->hard, current->pid); | ||
1301 | |||
1302 | if (ue->hard) | ||
1303 | __xfrm_state_delete(x); | ||
1304 | out: | ||
1305 | spin_unlock_bh(&x->lock); | ||
1306 | xfrm_state_put(x); | ||
1307 | return err; | ||
1308 | } | ||
1309 | |||
1310 | static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1311 | { | ||
1312 | struct xfrm_policy *xp; | ||
1313 | struct xfrm_user_tmpl *ut; | ||
1314 | int i; | ||
1315 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | ||
1316 | |||
1317 | struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); | ||
1318 | struct xfrm_state *x = xfrm_state_alloc(); | ||
1319 | int err = -ENOMEM; | ||
1320 | |||
1321 | if (!x) | ||
1322 | return err; | ||
1323 | |||
1324 | err = verify_newpolicy_info(&ua->policy); | ||
1325 | if (err) { | ||
1326 | printk("BAD policy passed\n"); | ||
1327 | kfree(x); | ||
1328 | return err; | ||
1329 | } | ||
1330 | |||
1331 | /* build an XP */ | ||
1332 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { | ||
1333 | kfree(x); | ||
1334 | return err; | ||
1335 | } | ||
1336 | |||
1337 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | ||
1338 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | ||
1339 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | ||
1340 | |||
1341 | ut = RTA_DATA(rt); | ||
1342 | /* extract the templates and for each call km_key */ | ||
1343 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | ||
1344 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | ||
1345 | memcpy(&x->id, &t->id, sizeof(x->id)); | ||
1346 | x->props.mode = t->mode; | ||
1347 | x->props.reqid = t->reqid; | ||
1348 | x->props.family = ut->family; | ||
1349 | t->aalgos = ua->aalgos; | ||
1350 | t->ealgos = ua->ealgos; | ||
1351 | t->calgos = ua->calgos; | ||
1352 | err = km_query(x, t, xp); | ||
1353 | |||
1354 | } | ||
1355 | |||
1356 | kfree(x); | ||
1357 | kfree(xp); | ||
1358 | |||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | |||
1040 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) | 1363 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) |
1041 | 1364 | ||
1042 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | 1365 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { |
@@ -1054,6 +1377,8 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1054 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), | 1377 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), |
1055 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), | 1378 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), |
1056 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1379 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1380 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | ||
1381 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | ||
1057 | }; | 1382 | }; |
1058 | 1383 | ||
1059 | #undef XMSGSIZE | 1384 | #undef XMSGSIZE |
@@ -1071,10 +1396,15 @@ static struct xfrm_link { | |||
1071 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, | 1396 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, |
1072 | .dump = xfrm_dump_policy }, | 1397 | .dump = xfrm_dump_policy }, |
1073 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, | 1398 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, |
1399 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, | ||
1400 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, | ||
1074 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 1401 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
1075 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, | 1402 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, |
1403 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, | ||
1076 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, | 1404 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, |
1077 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, | 1405 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, |
1406 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, | ||
1407 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, | ||
1078 | }; | 1408 | }; |
1079 | 1409 | ||
1080 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 1410 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) |
@@ -1156,26 +1486,26 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) | |||
1156 | unsigned int qlen = 0; | 1486 | unsigned int qlen = 0; |
1157 | 1487 | ||
1158 | do { | 1488 | do { |
1159 | down(&xfrm_cfg_sem); | 1489 | mutex_lock(&xfrm_cfg_mutex); |
1160 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); | 1490 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); |
1161 | up(&xfrm_cfg_sem); | 1491 | mutex_unlock(&xfrm_cfg_mutex); |
1162 | 1492 | ||
1163 | } while (qlen); | 1493 | } while (qlen); |
1164 | } | 1494 | } |
1165 | 1495 | ||
1166 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) | 1496 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
1167 | { | 1497 | { |
1168 | struct xfrm_user_expire *ue; | 1498 | struct xfrm_user_expire *ue; |
1169 | struct nlmsghdr *nlh; | 1499 | struct nlmsghdr *nlh; |
1170 | unsigned char *b = skb->tail; | 1500 | unsigned char *b = skb->tail; |
1171 | 1501 | ||
1172 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE, | 1502 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, |
1173 | sizeof(*ue)); | 1503 | sizeof(*ue)); |
1174 | ue = NLMSG_DATA(nlh); | 1504 | ue = NLMSG_DATA(nlh); |
1175 | nlh->nlmsg_flags = 0; | 1505 | nlh->nlmsg_flags = 0; |
1176 | 1506 | ||
1177 | copy_to_user_state(x, &ue->state); | 1507 | copy_to_user_state(x, &ue->state); |
1178 | ue->hard = (hard != 0) ? 1 : 0; | 1508 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
1179 | 1509 | ||
1180 | nlh->nlmsg_len = skb->tail - b; | 1510 | nlh->nlmsg_len = skb->tail - b; |
1181 | return skb->len; | 1511 | return skb->len; |
@@ -1194,13 +1524,31 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | |||
1194 | if (skb == NULL) | 1524 | if (skb == NULL) |
1195 | return -ENOMEM; | 1525 | return -ENOMEM; |
1196 | 1526 | ||
1197 | if (build_expire(skb, x, c->data.hard) < 0) | 1527 | if (build_expire(skb, x, c) < 0) |
1198 | BUG(); | 1528 | BUG(); |
1199 | 1529 | ||
1200 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1530 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
1201 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 1531 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
1202 | } | 1532 | } |
1203 | 1533 | ||
1534 | static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) | ||
1535 | { | ||
1536 | struct sk_buff *skb; | ||
1537 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | ||
1538 | |||
1539 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | ||
1540 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | ||
1541 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1542 | if (skb == NULL) | ||
1543 | return -ENOMEM; | ||
1544 | |||
1545 | if (build_aevent(skb, x, c) < 0) | ||
1546 | BUG(); | ||
1547 | |||
1548 | NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; | ||
1549 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); | ||
1550 | } | ||
1551 | |||
1204 | static int xfrm_notify_sa_flush(struct km_event *c) | 1552 | static int xfrm_notify_sa_flush(struct km_event *c) |
1205 | { | 1553 | { |
1206 | struct xfrm_usersa_flush *p; | 1554 | struct xfrm_usersa_flush *p; |
@@ -1313,6 +1661,8 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) | |||
1313 | switch (c->event) { | 1661 | switch (c->event) { |
1314 | case XFRM_MSG_EXPIRE: | 1662 | case XFRM_MSG_EXPIRE: |
1315 | return xfrm_exp_state_notify(x, c); | 1663 | return xfrm_exp_state_notify(x, c); |
1664 | case XFRM_MSG_NEWAE: | ||
1665 | return xfrm_aevent_state_notify(x, c); | ||
1316 | case XFRM_MSG_DELSA: | 1666 | case XFRM_MSG_DELSA: |
1317 | case XFRM_MSG_UPDSA: | 1667 | case XFRM_MSG_UPDSA: |
1318 | case XFRM_MSG_NEWSA: | 1668 | case XFRM_MSG_NEWSA: |
@@ -1443,13 +1793,14 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1443 | } | 1793 | } |
1444 | 1794 | ||
1445 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | 1795 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, |
1446 | int dir, int hard) | 1796 | int dir, struct km_event *c) |
1447 | { | 1797 | { |
1448 | struct xfrm_user_polexpire *upe; | 1798 | struct xfrm_user_polexpire *upe; |
1449 | struct nlmsghdr *nlh; | 1799 | struct nlmsghdr *nlh; |
1800 | int hard = c->data.hard; | ||
1450 | unsigned char *b = skb->tail; | 1801 | unsigned char *b = skb->tail; |
1451 | 1802 | ||
1452 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); | 1803 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); |
1453 | upe = NLMSG_DATA(nlh); | 1804 | upe = NLMSG_DATA(nlh); |
1454 | nlh->nlmsg_flags = 0; | 1805 | nlh->nlmsg_flags = 0; |
1455 | 1806 | ||
@@ -1480,7 +1831,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve | |||
1480 | if (skb == NULL) | 1831 | if (skb == NULL) |
1481 | return -ENOMEM; | 1832 | return -ENOMEM; |
1482 | 1833 | ||
1483 | if (build_polexpire(skb, xp, dir, c->data.hard) < 0) | 1834 | if (build_polexpire(skb, xp, dir, c) < 0) |
1484 | BUG(); | 1835 | BUG(); |
1485 | 1836 | ||
1486 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1837 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
@@ -1596,12 +1947,15 @@ static struct xfrm_mgr netlink_mgr = { | |||
1596 | 1947 | ||
1597 | static int __init xfrm_user_init(void) | 1948 | static int __init xfrm_user_init(void) |
1598 | { | 1949 | { |
1950 | struct sock *nlsk; | ||
1951 | |||
1599 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 1952 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); |
1600 | 1953 | ||
1601 | xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 1954 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
1602 | xfrm_netlink_rcv, THIS_MODULE); | 1955 | xfrm_netlink_rcv, THIS_MODULE); |
1603 | if (xfrm_nl == NULL) | 1956 | if (nlsk == NULL) |
1604 | return -ENOMEM; | 1957 | return -ENOMEM; |
1958 | rcu_assign_pointer(xfrm_nl, nlsk); | ||
1605 | 1959 | ||
1606 | xfrm_register_km(&netlink_mgr); | 1960 | xfrm_register_km(&netlink_mgr); |
1607 | 1961 | ||
@@ -1610,11 +1964,16 @@ static int __init xfrm_user_init(void) | |||
1610 | 1964 | ||
1611 | static void __exit xfrm_user_exit(void) | 1965 | static void __exit xfrm_user_exit(void) |
1612 | { | 1966 | { |
1967 | struct sock *nlsk = xfrm_nl; | ||
1968 | |||
1613 | xfrm_unregister_km(&netlink_mgr); | 1969 | xfrm_unregister_km(&netlink_mgr); |
1614 | sock_release(xfrm_nl->sk_socket); | 1970 | rcu_assign_pointer(xfrm_nl, NULL); |
1971 | synchronize_rcu(); | ||
1972 | sock_release(nlsk->sk_socket); | ||
1615 | } | 1973 | } |
1616 | 1974 | ||
1617 | module_init(xfrm_user_init); | 1975 | module_init(xfrm_user_init); |
1618 | module_exit(xfrm_user_exit); | 1976 | module_exit(xfrm_user_exit); |
1619 | MODULE_LICENSE("GPL"); | 1977 | MODULE_LICENSE("GPL"); |
1620 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); | 1978 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); |
1979 | |||