diff options
author | Jamal Hadi Salim <hadi@cyberus.ca> | 2005-06-19 01:42:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-06-19 01:42:13 -0400 |
commit | 26b15dad9f1c19d6d4f7b999b07eaa6d98e4b375 (patch) | |
tree | 2ca3039488d9df023fb84eaa7c1f52aa8d1ce69c | |
parent | 3aa3dfb372576f30835a94409556e3c8681b5756 (diff) |
[IPSEC] Add complete xfrm event notification
Heres the final patch.
What this patch provides
- netlink xfrm events
- ability to have events generated by netlink propagated to pfkey
and vice versa.
- fixes the acquire lets-be-happy-with-one-success issue
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | include/linux/xfrm.h | 2 | ||||
-rw-r--r-- | include/net/xfrm.h | 29 | ||||
-rw-r--r-- | net/key/af_key.c | 357 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 74 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 272 |
5 files changed, 616 insertions, 118 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index fd2ef742a9fd..03bc600516ea 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -257,5 +257,7 @@ struct xfrm_usersa_flush { | |||
257 | 257 | ||
258 | #define XFRMGRP_ACQUIRE 1 | 258 | #define XFRMGRP_ACQUIRE 1 |
259 | #define XFRMGRP_EXPIRE 2 | 259 | #define XFRMGRP_EXPIRE 2 |
260 | #define XFRMGRP_SA 4 | ||
261 | #define XFRMGRP_POLICY 8 | ||
260 | 262 | ||
261 | #endif /* _LINUX_XFRM_H */ | 263 | #endif /* _LINUX_XFRM_H */ |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index d675836ba6c3..a159655ebede 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -158,6 +158,27 @@ enum { | |||
158 | XFRM_STATE_DEAD | 158 | XFRM_STATE_DEAD |
159 | }; | 159 | }; |
160 | 160 | ||
161 | /* events that could be sent by kernel */ | ||
162 | enum { | ||
163 | XFRM_SAP_INVALID, | ||
164 | XFRM_SAP_EXPIRED, | ||
165 | XFRM_SAP_ADDED, | ||
166 | XFRM_SAP_UPDATED, | ||
167 | XFRM_SAP_DELETED, | ||
168 | XFRM_SAP_FLUSHED, | ||
169 | __XFRM_SAP_MAX | ||
170 | }; | ||
171 | #define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1) | ||
172 | |||
173 | /* callback structure passed from either netlink or pfkey */ | ||
174 | struct km_event | ||
175 | { | ||
176 | u32 data; | ||
177 | u32 seq; | ||
178 | u32 pid; | ||
179 | u32 event; | ||
180 | }; | ||
181 | |||
161 | struct xfrm_type; | 182 | struct xfrm_type; |
162 | struct xfrm_dst; | 183 | struct xfrm_dst; |
163 | struct xfrm_policy_afinfo { | 184 | struct xfrm_policy_afinfo { |
@@ -179,6 +200,8 @@ struct xfrm_policy_afinfo { | |||
179 | 200 | ||
180 | extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); | 201 | extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); |
181 | extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo); | 202 | extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo); |
203 | extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c); | ||
204 | extern void km_state_notify(struct xfrm_state *x, struct km_event *c); | ||
182 | 205 | ||
183 | #define XFRM_ACQ_EXPIRES 30 | 206 | #define XFRM_ACQ_EXPIRES 30 |
184 | 207 | ||
@@ -290,11 +313,11 @@ struct xfrm_mgr | |||
290 | { | 313 | { |
291 | struct list_head list; | 314 | struct list_head list; |
292 | char *id; | 315 | char *id; |
293 | int (*notify)(struct xfrm_state *x, int event); | 316 | int (*notify)(struct xfrm_state *x, struct km_event *c); |
294 | int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); | 317 | int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); |
295 | struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); | 318 | struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); |
296 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); | 319 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); |
297 | int (*notify_policy)(struct xfrm_policy *x, int dir, int event); | 320 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); |
298 | }; | 321 | }; |
299 | 322 | ||
300 | extern int xfrm_register_km(struct xfrm_mgr *km); | 323 | extern int xfrm_register_km(struct xfrm_mgr *km); |
@@ -817,7 +840,7 @@ extern int xfrm_state_add(struct xfrm_state *x); | |||
817 | extern int xfrm_state_update(struct xfrm_state *x); | 840 | extern int xfrm_state_update(struct xfrm_state *x); |
818 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); | 841 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); |
819 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); | 842 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); |
820 | extern void xfrm_state_delete(struct xfrm_state *x); | 843 | extern int xfrm_state_delete(struct xfrm_state *x); |
821 | extern void xfrm_state_flush(u8 proto); | 844 | extern void xfrm_state_flush(u8 proto); |
822 | extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); | 845 | extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); |
823 | extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); | 846 | extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); |
diff --git a/net/key/af_key.c b/net/key/af_key.c index ce980aa94ed8..d086c117f5f0 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -1240,13 +1240,85 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg * | |||
1240 | return 0; | 1240 | return 0; |
1241 | } | 1241 | } |
1242 | 1242 | ||
1243 | static inline int event2poltype(int event) | ||
1244 | { | ||
1245 | switch (event) { | ||
1246 | case XFRM_SAP_DELETED: | ||
1247 | return SADB_X_SPDDELETE; | ||
1248 | case XFRM_SAP_ADDED: | ||
1249 | return SADB_X_SPDADD; | ||
1250 | case XFRM_SAP_UPDATED: | ||
1251 | return SADB_X_SPDUPDATE; | ||
1252 | case XFRM_SAP_EXPIRED: | ||
1253 | // return SADB_X_SPDEXPIRE; | ||
1254 | default: | ||
1255 | printk("pfkey: Unknown policy event %d\n", event); | ||
1256 | break; | ||
1257 | } | ||
1258 | |||
1259 | return 0; | ||
1260 | } | ||
1261 | |||
1262 | static inline int event2keytype(int event) | ||
1263 | { | ||
1264 | switch (event) { | ||
1265 | case XFRM_SAP_DELETED: | ||
1266 | return SADB_DELETE; | ||
1267 | case XFRM_SAP_ADDED: | ||
1268 | return SADB_ADD; | ||
1269 | case XFRM_SAP_UPDATED: | ||
1270 | return SADB_UPDATE; | ||
1271 | case XFRM_SAP_EXPIRED: | ||
1272 | return SADB_EXPIRE; | ||
1273 | default: | ||
1274 | printk("pfkey: Unknown SA event %d\n", event); | ||
1275 | break; | ||
1276 | } | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | /* ADD/UPD/DEL */ | ||
1282 | static int key_notify_sa(struct xfrm_state *x, struct km_event *c) | ||
1283 | { | ||
1284 | struct sk_buff *skb; | ||
1285 | struct sadb_msg *hdr; | ||
1286 | int hsc = 3; | ||
1287 | |||
1288 | if (c->event == XFRM_SAP_DELETED) | ||
1289 | hsc = 0; | ||
1290 | |||
1291 | if (c->event == XFRM_SAP_EXPIRED) { | ||
1292 | if (c->data) | ||
1293 | hsc = 2; | ||
1294 | else | ||
1295 | hsc = 1; | ||
1296 | } | ||
1297 | |||
1298 | skb = pfkey_xfrm_state2msg(x, 0, hsc); | ||
1299 | |||
1300 | if (IS_ERR(skb)) | ||
1301 | return PTR_ERR(skb); | ||
1302 | |||
1303 | hdr = (struct sadb_msg *) skb->data; | ||
1304 | hdr->sadb_msg_version = PF_KEY_V2; | ||
1305 | hdr->sadb_msg_type = event2keytype(c->event); | ||
1306 | hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); | ||
1307 | hdr->sadb_msg_errno = 0; | ||
1308 | hdr->sadb_msg_reserved = 0; | ||
1309 | hdr->sadb_msg_seq = c->seq; | ||
1310 | hdr->sadb_msg_pid = c->pid; | ||
1311 | |||
1312 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); | ||
1313 | |||
1314 | return 0; | ||
1315 | } | ||
1243 | 1316 | ||
1244 | static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1317 | static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
1245 | { | 1318 | { |
1246 | struct sk_buff *out_skb; | ||
1247 | struct sadb_msg *out_hdr; | ||
1248 | struct xfrm_state *x; | 1319 | struct xfrm_state *x; |
1249 | int err; | 1320 | int err; |
1321 | struct km_event c; | ||
1250 | 1322 | ||
1251 | xfrm_probe_algs(); | 1323 | xfrm_probe_algs(); |
1252 | 1324 | ||
@@ -1254,6 +1326,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, | |||
1254 | if (IS_ERR(x)) | 1326 | if (IS_ERR(x)) |
1255 | return PTR_ERR(x); | 1327 | return PTR_ERR(x); |
1256 | 1328 | ||
1329 | xfrm_state_hold(x); | ||
1257 | if (hdr->sadb_msg_type == SADB_ADD) | 1330 | if (hdr->sadb_msg_type == SADB_ADD) |
1258 | err = xfrm_state_add(x); | 1331 | err = xfrm_state_add(x); |
1259 | else | 1332 | else |
@@ -1265,27 +1338,23 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, | |||
1265 | return err; | 1338 | return err; |
1266 | } | 1339 | } |
1267 | 1340 | ||
1268 | out_skb = pfkey_xfrm_state2msg(x, 0, 3); | 1341 | if (hdr->sadb_msg_type == SADB_ADD) |
1269 | if (IS_ERR(out_skb)) | 1342 | c.event = XFRM_SAP_ADDED; |
1270 | return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */ | 1343 | else |
1271 | 1344 | c.event = XFRM_SAP_UPDATED; | |
1272 | out_hdr = (struct sadb_msg *) out_skb->data; | 1345 | c.seq = hdr->sadb_msg_seq; |
1273 | out_hdr->sadb_msg_version = hdr->sadb_msg_version; | 1346 | c.pid = hdr->sadb_msg_pid; |
1274 | out_hdr->sadb_msg_type = hdr->sadb_msg_type; | 1347 | km_state_notify(x, &c); |
1275 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); | 1348 | xfrm_state_put(x); |
1276 | out_hdr->sadb_msg_errno = 0; | ||
1277 | out_hdr->sadb_msg_reserved = 0; | ||
1278 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | ||
1279 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | ||
1280 | |||
1281 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); | ||
1282 | 1349 | ||
1283 | return 0; | 1350 | return err; |
1284 | } | 1351 | } |
1285 | 1352 | ||
1286 | static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1353 | static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
1287 | { | 1354 | { |
1288 | struct xfrm_state *x; | 1355 | struct xfrm_state *x; |
1356 | struct km_event c; | ||
1357 | int err; | ||
1289 | 1358 | ||
1290 | if (!ext_hdrs[SADB_EXT_SA-1] || | 1359 | if (!ext_hdrs[SADB_EXT_SA-1] || |
1291 | !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 1360 | !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
@@ -1301,13 +1370,19 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
1301 | return -EPERM; | 1370 | return -EPERM; |
1302 | } | 1371 | } |
1303 | 1372 | ||
1304 | xfrm_state_delete(x); | 1373 | err = xfrm_state_delete(x); |
1305 | xfrm_state_put(x); | 1374 | if (err < 0) { |
1375 | xfrm_state_put(x); | ||
1376 | return err; | ||
1377 | } | ||
1306 | 1378 | ||
1307 | pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, | 1379 | c.seq = hdr->sadb_msg_seq; |
1308 | BROADCAST_ALL, sk); | 1380 | c.pid = hdr->sadb_msg_pid; |
1381 | c.event = XFRM_SAP_DELETED; | ||
1382 | km_state_notify(x, &c); | ||
1383 | xfrm_state_put(x); | ||
1309 | 1384 | ||
1310 | return 0; | 1385 | return err; |
1311 | } | 1386 | } |
1312 | 1387 | ||
1313 | static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1388 | static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
@@ -1445,28 +1520,42 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
1445 | return 0; | 1520 | return 0; |
1446 | } | 1521 | } |
1447 | 1522 | ||
1523 | static int key_notify_sa_flush(struct km_event *c) | ||
1524 | { | ||
1525 | struct sk_buff *skb; | ||
1526 | struct sadb_msg *hdr; | ||
1527 | |||
1528 | skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); | ||
1529 | if (!skb) | ||
1530 | return -ENOBUFS; | ||
1531 | hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); | ||
1532 | hdr->sadb_msg_satype = pfkey_proto2satype(c->data); | ||
1533 | hdr->sadb_msg_seq = c->seq; | ||
1534 | hdr->sadb_msg_pid = c->pid; | ||
1535 | hdr->sadb_msg_version = PF_KEY_V2; | ||
1536 | hdr->sadb_msg_errno = (uint8_t) 0; | ||
1537 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | ||
1538 | |||
1539 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); | ||
1540 | |||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1448 | static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1544 | static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
1449 | { | 1545 | { |
1450 | unsigned proto; | 1546 | unsigned proto; |
1451 | struct sk_buff *skb_out; | 1547 | struct km_event c; |
1452 | struct sadb_msg *hdr_out; | ||
1453 | 1548 | ||
1454 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); | 1549 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); |
1455 | if (proto == 0) | 1550 | if (proto == 0) |
1456 | return -EINVAL; | 1551 | return -EINVAL; |
1457 | 1552 | ||
1458 | skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); | ||
1459 | if (!skb_out) | ||
1460 | return -ENOBUFS; | ||
1461 | |||
1462 | xfrm_state_flush(proto); | 1553 | xfrm_state_flush(proto); |
1463 | 1554 | c.data = proto; | |
1464 | hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); | 1555 | c.seq = hdr->sadb_msg_seq; |
1465 | pfkey_hdr_dup(hdr_out, hdr); | 1556 | c.pid = hdr->sadb_msg_pid; |
1466 | hdr_out->sadb_msg_errno = (uint8_t) 0; | 1557 | c.event = XFRM_SAP_FLUSHED; |
1467 | hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 1558 | km_state_notify(NULL, &c); |
1468 | |||
1469 | pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL); | ||
1470 | 1559 | ||
1471 | return 0; | 1560 | return 0; |
1472 | } | 1561 | } |
@@ -1859,6 +1948,35 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i | |||
1859 | hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); | 1948 | hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); |
1860 | } | 1949 | } |
1861 | 1950 | ||
1951 | static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) | ||
1952 | { | ||
1953 | struct sk_buff *out_skb; | ||
1954 | struct sadb_msg *out_hdr; | ||
1955 | int err; | ||
1956 | |||
1957 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | ||
1958 | if (IS_ERR(out_skb)) { | ||
1959 | err = PTR_ERR(out_skb); | ||
1960 | goto out; | ||
1961 | } | ||
1962 | pfkey_xfrm_policy2msg(out_skb, xp, dir); | ||
1963 | |||
1964 | out_hdr = (struct sadb_msg *) out_skb->data; | ||
1965 | out_hdr->sadb_msg_version = PF_KEY_V2; | ||
1966 | |||
1967 | if (c->data && c->event == XFRM_SAP_DELETED) | ||
1968 | out_hdr->sadb_msg_type = SADB_X_SPDDELETE2; | ||
1969 | else | ||
1970 | out_hdr->sadb_msg_type = event2poltype(c->event); | ||
1971 | out_hdr->sadb_msg_errno = 0; | ||
1972 | out_hdr->sadb_msg_seq = c->seq; | ||
1973 | out_hdr->sadb_msg_pid = c->pid; | ||
1974 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL); | ||
1975 | out: | ||
1976 | return 0; | ||
1977 | |||
1978 | } | ||
1979 | |||
1862 | static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1980 | static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
1863 | { | 1981 | { |
1864 | int err; | 1982 | int err; |
@@ -1866,8 +1984,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
1866 | struct sadb_address *sa; | 1984 | struct sadb_address *sa; |
1867 | struct sadb_x_policy *pol; | 1985 | struct sadb_x_policy *pol; |
1868 | struct xfrm_policy *xp; | 1986 | struct xfrm_policy *xp; |
1869 | struct sk_buff *out_skb; | 1987 | struct km_event c; |
1870 | struct sadb_msg *out_hdr; | ||
1871 | 1988 | ||
1872 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 1989 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
1873 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || | 1990 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || |
@@ -1935,31 +2052,23 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
1935 | (err = parse_ipsecrequests(xp, pol)) < 0) | 2052 | (err = parse_ipsecrequests(xp, pol)) < 0) |
1936 | goto out; | 2053 | goto out; |
1937 | 2054 | ||
1938 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | ||
1939 | if (IS_ERR(out_skb)) { | ||
1940 | err = PTR_ERR(out_skb); | ||
1941 | goto out; | ||
1942 | } | ||
1943 | |||
1944 | err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, | 2055 | err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, |
1945 | hdr->sadb_msg_type != SADB_X_SPDUPDATE); | 2056 | hdr->sadb_msg_type != SADB_X_SPDUPDATE); |
1946 | if (err) { | 2057 | if (err) { |
1947 | kfree_skb(out_skb); | 2058 | kfree(xp); |
1948 | goto out; | 2059 | return err; |
1949 | } | 2060 | } |
1950 | 2061 | ||
1951 | pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1); | 2062 | if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) |
2063 | c.event = XFRM_SAP_UPDATED; | ||
2064 | else | ||
2065 | c.event = XFRM_SAP_ADDED; | ||
1952 | 2066 | ||
1953 | xfrm_pol_put(xp); | 2067 | c.seq = hdr->sadb_msg_seq; |
2068 | c.pid = hdr->sadb_msg_pid; | ||
1954 | 2069 | ||
1955 | out_hdr = (struct sadb_msg *) out_skb->data; | 2070 | km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); |
1956 | out_hdr->sadb_msg_version = hdr->sadb_msg_version; | 2071 | xfrm_pol_put(xp); |
1957 | out_hdr->sadb_msg_type = hdr->sadb_msg_type; | ||
1958 | out_hdr->sadb_msg_satype = 0; | ||
1959 | out_hdr->sadb_msg_errno = 0; | ||
1960 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | ||
1961 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | ||
1962 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); | ||
1963 | return 0; | 2072 | return 0; |
1964 | 2073 | ||
1965 | out: | 2074 | out: |
@@ -1973,9 +2082,8 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
1973 | struct sadb_address *sa; | 2082 | struct sadb_address *sa; |
1974 | struct sadb_x_policy *pol; | 2083 | struct sadb_x_policy *pol; |
1975 | struct xfrm_policy *xp; | 2084 | struct xfrm_policy *xp; |
1976 | struct sk_buff *out_skb; | ||
1977 | struct sadb_msg *out_hdr; | ||
1978 | struct xfrm_selector sel; | 2085 | struct xfrm_selector sel; |
2086 | struct km_event c; | ||
1979 | 2087 | ||
1980 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 2088 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
1981 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || | 2089 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || |
@@ -2010,25 +2118,40 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2010 | 2118 | ||
2011 | err = 0; | 2119 | err = 0; |
2012 | 2120 | ||
2121 | c.seq = hdr->sadb_msg_seq; | ||
2122 | c.pid = hdr->sadb_msg_pid; | ||
2123 | c.event = XFRM_SAP_DELETED; | ||
2124 | km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); | ||
2125 | |||
2126 | xfrm_pol_put(xp); | ||
2127 | return err; | ||
2128 | } | ||
2129 | |||
2130 | static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb_msg *hdr, int dir) | ||
2131 | { | ||
2132 | int err; | ||
2133 | struct sk_buff *out_skb; | ||
2134 | struct sadb_msg *out_hdr; | ||
2135 | err = 0; | ||
2136 | |||
2013 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | 2137 | out_skb = pfkey_xfrm_policy2msg_prep(xp); |
2014 | if (IS_ERR(out_skb)) { | 2138 | if (IS_ERR(out_skb)) { |
2015 | err = PTR_ERR(out_skb); | 2139 | err = PTR_ERR(out_skb); |
2016 | goto out; | 2140 | goto out; |
2017 | } | 2141 | } |
2018 | pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1); | 2142 | pfkey_xfrm_policy2msg(out_skb, xp, dir); |
2019 | 2143 | ||
2020 | out_hdr = (struct sadb_msg *) out_skb->data; | 2144 | out_hdr = (struct sadb_msg *) out_skb->data; |
2021 | out_hdr->sadb_msg_version = hdr->sadb_msg_version; | 2145 | out_hdr->sadb_msg_version = hdr->sadb_msg_version; |
2022 | out_hdr->sadb_msg_type = SADB_X_SPDDELETE; | 2146 | out_hdr->sadb_msg_type = hdr->sadb_msg_type; |
2023 | out_hdr->sadb_msg_satype = 0; | 2147 | out_hdr->sadb_msg_satype = 0; |
2024 | out_hdr->sadb_msg_errno = 0; | 2148 | out_hdr->sadb_msg_errno = 0; |
2025 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | 2149 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; |
2026 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | 2150 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; |
2027 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); | 2151 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); |
2028 | err = 0; | 2152 | err = 0; |
2029 | 2153 | ||
2030 | out: | 2154 | out: |
2031 | xfrm_pol_put(xp); | ||
2032 | return err; | 2155 | return err; |
2033 | } | 2156 | } |
2034 | 2157 | ||
@@ -2037,8 +2160,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
2037 | int err; | 2160 | int err; |
2038 | struct sadb_x_policy *pol; | 2161 | struct sadb_x_policy *pol; |
2039 | struct xfrm_policy *xp; | 2162 | struct xfrm_policy *xp; |
2040 | struct sk_buff *out_skb; | 2163 | struct km_event c; |
2041 | struct sadb_msg *out_hdr; | ||
2042 | 2164 | ||
2043 | if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL) | 2165 | if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL) |
2044 | return -EINVAL; | 2166 | return -EINVAL; |
@@ -2050,24 +2172,16 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
2050 | 2172 | ||
2051 | err = 0; | 2173 | err = 0; |
2052 | 2174 | ||
2053 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | 2175 | c.seq = hdr->sadb_msg_seq; |
2054 | if (IS_ERR(out_skb)) { | 2176 | c.pid = hdr->sadb_msg_pid; |
2055 | err = PTR_ERR(out_skb); | 2177 | if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) { |
2056 | goto out; | 2178 | c.data = 1; // to signal pfkey of SADB_X_SPDDELETE2 |
2179 | c.event = XFRM_SAP_DELETED; | ||
2180 | km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); | ||
2181 | } else { | ||
2182 | err = key_pol_get_resp(sk, xp, hdr, pol->sadb_x_policy_dir-1); | ||
2057 | } | 2183 | } |
2058 | pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1); | ||
2059 | 2184 | ||
2060 | out_hdr = (struct sadb_msg *) out_skb->data; | ||
2061 | out_hdr->sadb_msg_version = hdr->sadb_msg_version; | ||
2062 | out_hdr->sadb_msg_type = hdr->sadb_msg_type; | ||
2063 | out_hdr->sadb_msg_satype = 0; | ||
2064 | out_hdr->sadb_msg_errno = 0; | ||
2065 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | ||
2066 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | ||
2067 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk); | ||
2068 | err = 0; | ||
2069 | |||
2070 | out: | ||
2071 | xfrm_pol_put(xp); | 2185 | xfrm_pol_put(xp); |
2072 | return err; | 2186 | return err; |
2073 | } | 2187 | } |
@@ -2102,22 +2216,34 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg * | |||
2102 | return xfrm_policy_walk(dump_sp, &data); | 2216 | return xfrm_policy_walk(dump_sp, &data); |
2103 | } | 2217 | } |
2104 | 2218 | ||
2105 | static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 2219 | static int key_notify_policy_flush(struct km_event *c) |
2106 | { | 2220 | { |
2107 | struct sk_buff *skb_out; | 2221 | struct sk_buff *skb_out; |
2108 | struct sadb_msg *hdr_out; | 2222 | struct sadb_msg *hdr; |
2109 | 2223 | ||
2110 | skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); | 2224 | skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); |
2111 | if (!skb_out) | 2225 | if (!skb_out) |
2112 | return -ENOBUFS; | 2226 | return -ENOBUFS; |
2227 | hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); | ||
2228 | hdr->sadb_msg_seq = c->seq; | ||
2229 | hdr->sadb_msg_pid = c->pid; | ||
2230 | hdr->sadb_msg_version = PF_KEY_V2; | ||
2231 | hdr->sadb_msg_errno = (uint8_t) 0; | ||
2232 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | ||
2233 | pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL); | ||
2234 | return 0; | ||
2113 | 2235 | ||
2114 | xfrm_policy_flush(); | 2236 | } |
2237 | |||
2238 | static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | ||
2239 | { | ||
2240 | struct km_event c; | ||
2115 | 2241 | ||
2116 | hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); | 2242 | xfrm_policy_flush(); |
2117 | pfkey_hdr_dup(hdr_out, hdr); | 2243 | c.event = XFRM_SAP_FLUSHED; |
2118 | hdr_out->sadb_msg_errno = (uint8_t) 0; | 2244 | c.pid = hdr->sadb_msg_pid; |
2119 | hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 2245 | c.seq = hdr->sadb_msg_seq; |
2120 | pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL); | 2246 | km_policy_notify(NULL, 0, &c); |
2121 | 2247 | ||
2122 | return 0; | 2248 | return 0; |
2123 | } | 2249 | } |
@@ -2317,11 +2443,23 @@ static void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) | |||
2317 | } | 2443 | } |
2318 | } | 2444 | } |
2319 | 2445 | ||
2320 | static int pfkey_send_notify(struct xfrm_state *x, int hard) | 2446 | static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c) |
2447 | { | ||
2448 | return 0; | ||
2449 | } | ||
2450 | |||
2451 | static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) | ||
2321 | { | 2452 | { |
2322 | struct sk_buff *out_skb; | 2453 | struct sk_buff *out_skb; |
2323 | struct sadb_msg *out_hdr; | 2454 | struct sadb_msg *out_hdr; |
2324 | int hsc = (hard ? 2 : 1); | 2455 | int hard; |
2456 | int hsc; | ||
2457 | |||
2458 | hard = c->data; | ||
2459 | if (hard) | ||
2460 | hsc = 2; | ||
2461 | else | ||
2462 | hsc = 1; | ||
2325 | 2463 | ||
2326 | out_skb = pfkey_xfrm_state2msg(x, 0, hsc); | 2464 | out_skb = pfkey_xfrm_state2msg(x, 0, hsc); |
2327 | if (IS_ERR(out_skb)) | 2465 | if (IS_ERR(out_skb)) |
@@ -2340,6 +2478,44 @@ static int pfkey_send_notify(struct xfrm_state *x, int hard) | |||
2340 | return 0; | 2478 | return 0; |
2341 | } | 2479 | } |
2342 | 2480 | ||
2481 | static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) | ||
2482 | { | ||
2483 | switch (c->event) { | ||
2484 | case XFRM_SAP_EXPIRED: | ||
2485 | return key_notify_sa_expire(x, c); | ||
2486 | case XFRM_SAP_DELETED: | ||
2487 | case XFRM_SAP_ADDED: | ||
2488 | case XFRM_SAP_UPDATED: | ||
2489 | return key_notify_sa(x, c); | ||
2490 | case XFRM_SAP_FLUSHED: | ||
2491 | return key_notify_sa_flush(c); | ||
2492 | default: | ||
2493 | printk("pfkey: Unknown SA event %d\n", c->event); | ||
2494 | break; | ||
2495 | } | ||
2496 | |||
2497 | return 0; | ||
2498 | } | ||
2499 | |||
2500 | static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) | ||
2501 | { | ||
2502 | switch (c->event) { | ||
2503 | case XFRM_SAP_EXPIRED: | ||
2504 | return key_notify_policy_expire(xp, c); | ||
2505 | case XFRM_SAP_DELETED: | ||
2506 | case XFRM_SAP_ADDED: | ||
2507 | case XFRM_SAP_UPDATED: | ||
2508 | return key_notify_policy(xp, dir, c); | ||
2509 | case XFRM_SAP_FLUSHED: | ||
2510 | return key_notify_policy_flush(c); | ||
2511 | default: | ||
2512 | printk("pfkey: Unknown policy event %d\n", c->event); | ||
2513 | break; | ||
2514 | } | ||
2515 | |||
2516 | return 0; | ||
2517 | } | ||
2518 | |||
2343 | static u32 get_acqseq(void) | 2519 | static u32 get_acqseq(void) |
2344 | { | 2520 | { |
2345 | u32 res; | 2521 | u32 res; |
@@ -2856,6 +3032,7 @@ static struct xfrm_mgr pfkeyv2_mgr = | |||
2856 | .acquire = pfkey_send_acquire, | 3032 | .acquire = pfkey_send_acquire, |
2857 | .compile_policy = pfkey_compile_policy, | 3033 | .compile_policy = pfkey_compile_policy, |
2858 | .new_mapping = pfkey_send_new_mapping, | 3034 | .new_mapping = pfkey_send_new_mapping, |
3035 | .notify_policy = pfkey_send_policy_notify, | ||
2859 | }; | 3036 | }; |
2860 | 3037 | ||
2861 | static void __exit ipsec_pfkey_exit(void) | 3038 | static void __exit ipsec_pfkey_exit(void) |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d11747c2a763..918a94c552a5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
50 | 50 | ||
51 | static int xfrm_state_gc_flush_bundles; | 51 | static int xfrm_state_gc_flush_bundles; |
52 | 52 | ||
53 | static void __xfrm_state_delete(struct xfrm_state *x); | 53 | static int __xfrm_state_delete(struct xfrm_state *x); |
54 | 54 | ||
55 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | 55 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); |
56 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 56 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
@@ -215,8 +215,10 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
215 | } | 215 | } |
216 | EXPORT_SYMBOL(__xfrm_state_destroy); | 216 | EXPORT_SYMBOL(__xfrm_state_destroy); |
217 | 217 | ||
218 | static void __xfrm_state_delete(struct xfrm_state *x) | 218 | static int __xfrm_state_delete(struct xfrm_state *x) |
219 | { | 219 | { |
220 | int err = -ESRCH; | ||
221 | |||
220 | if (x->km.state != XFRM_STATE_DEAD) { | 222 | if (x->km.state != XFRM_STATE_DEAD) { |
221 | x->km.state = XFRM_STATE_DEAD; | 223 | x->km.state = XFRM_STATE_DEAD; |
222 | spin_lock(&xfrm_state_lock); | 224 | spin_lock(&xfrm_state_lock); |
@@ -245,14 +247,21 @@ static void __xfrm_state_delete(struct xfrm_state *x) | |||
245 | * is what we are dropping here. | 247 | * is what we are dropping here. |
246 | */ | 248 | */ |
247 | atomic_dec(&x->refcnt); | 249 | atomic_dec(&x->refcnt); |
250 | err = 0; | ||
248 | } | 251 | } |
252 | |||
253 | return err; | ||
249 | } | 254 | } |
250 | 255 | ||
251 | void xfrm_state_delete(struct xfrm_state *x) | 256 | int xfrm_state_delete(struct xfrm_state *x) |
252 | { | 257 | { |
258 | int err; | ||
259 | |||
253 | spin_lock_bh(&x->lock); | 260 | spin_lock_bh(&x->lock); |
254 | __xfrm_state_delete(x); | 261 | err = __xfrm_state_delete(x); |
255 | spin_unlock_bh(&x->lock); | 262 | spin_unlock_bh(&x->lock); |
263 | |||
264 | return err; | ||
256 | } | 265 | } |
257 | EXPORT_SYMBOL(xfrm_state_delete); | 266 | EXPORT_SYMBOL(xfrm_state_delete); |
258 | 267 | ||
@@ -796,34 +805,60 @@ EXPORT_SYMBOL(xfrm_replay_advance); | |||
796 | static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); | 805 | static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); |
797 | static DEFINE_RWLOCK(xfrm_km_lock); | 806 | static DEFINE_RWLOCK(xfrm_km_lock); |
798 | 807 | ||
799 | static void km_state_expired(struct xfrm_state *x, int hard) | 808 | void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) |
800 | { | 809 | { |
801 | struct xfrm_mgr *km; | 810 | struct xfrm_mgr *km; |
802 | 811 | ||
803 | if (hard) | 812 | read_lock(&xfrm_km_lock); |
804 | x->km.state = XFRM_STATE_EXPIRED; | 813 | list_for_each_entry(km, &xfrm_km_list, list) |
805 | else | 814 | if (km->notify_policy) |
806 | x->km.dying = 1; | 815 | km->notify_policy(xp, dir, c); |
816 | read_unlock(&xfrm_km_lock); | ||
817 | } | ||
807 | 818 | ||
819 | void km_state_notify(struct xfrm_state *x, struct km_event *c) | ||
820 | { | ||
821 | struct xfrm_mgr *km; | ||
808 | read_lock(&xfrm_km_lock); | 822 | read_lock(&xfrm_km_lock); |
809 | list_for_each_entry(km, &xfrm_km_list, list) | 823 | list_for_each_entry(km, &xfrm_km_list, list) |
810 | km->notify(x, hard); | 824 | if (km->notify) |
825 | km->notify(x, c); | ||
811 | read_unlock(&xfrm_km_lock); | 826 | read_unlock(&xfrm_km_lock); |
827 | } | ||
828 | |||
829 | EXPORT_SYMBOL(km_policy_notify); | ||
830 | EXPORT_SYMBOL(km_state_notify); | ||
831 | |||
832 | static void km_state_expired(struct xfrm_state *x, int hard) | ||
833 | { | ||
834 | struct km_event c; | ||
835 | |||
836 | if (hard) | ||
837 | x->km.state = XFRM_STATE_EXPIRED; | ||
838 | else | ||
839 | x->km.dying = 1; | ||
840 | c.data = hard; | ||
841 | c.event = XFRM_SAP_EXPIRED; | ||
842 | km_state_notify(x, &c); | ||
812 | 843 | ||
813 | if (hard) | 844 | if (hard) |
814 | wake_up(&km_waitq); | 845 | wake_up(&km_waitq); |
815 | } | 846 | } |
816 | 847 | ||
848 | /* | ||
849 | * We send to all registered managers regardless of failure | ||
850 | * We are happy with one success | ||
851 | */ | ||
817 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) | 852 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) |
818 | { | 853 | { |
819 | int err = -EINVAL; | 854 | int err = -EINVAL, acqret; |
820 | struct xfrm_mgr *km; | 855 | struct xfrm_mgr *km; |
821 | 856 | ||
822 | read_lock(&xfrm_km_lock); | 857 | read_lock(&xfrm_km_lock); |
823 | list_for_each_entry(km, &xfrm_km_list, list) { | 858 | list_for_each_entry(km, &xfrm_km_list, list) { |
824 | err = km->acquire(x, t, pol, XFRM_POLICY_OUT); | 859 | acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); |
825 | if (!err) | 860 | if (!acqret) |
826 | break; | 861 | err = acqret; |
827 | } | 862 | } |
828 | read_unlock(&xfrm_km_lock); | 863 | read_unlock(&xfrm_km_lock); |
829 | return err; | 864 | return err; |
@@ -848,13 +883,12 @@ EXPORT_SYMBOL(km_new_mapping); | |||
848 | 883 | ||
849 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) | 884 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) |
850 | { | 885 | { |
851 | struct xfrm_mgr *km; | 886 | struct km_event c; |
852 | 887 | ||
853 | read_lock(&xfrm_km_lock); | 888 | c.data = hard; |
854 | list_for_each_entry(km, &xfrm_km_list, list) | 889 | c.data = hard; |
855 | if (km->notify_policy) | 890 | c.event = XFRM_SAP_EXPIRED; |
856 | km->notify_policy(pol, dir, hard); | 891 | km_policy_notify(pol, dir, &c); |
857 | read_unlock(&xfrm_km_lock); | ||
858 | 892 | ||
859 | if (hard) | 893 | if (hard) |
860 | wake_up(&km_waitq); | 894 | wake_up(&km_waitq); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 97509011c274..bd8e6882c083 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,27 @@ 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 | return err; | ||
297 | } | 300 | } |
298 | 301 | ||
302 | c.seq = nlh->nlmsg_seq; | ||
303 | c.pid = nlh->nlmsg_pid; | ||
304 | if (nlh->nlmsg_type == XFRM_MSG_NEWSA) | ||
305 | c.event = XFRM_SAP_ADDED; | ||
306 | else | ||
307 | c.event = XFRM_SAP_UPDATED; | ||
308 | |||
309 | km_state_notify(x, &c); | ||
310 | xfrm_state_put(x); | ||
311 | |||
299 | return err; | 312 | return err; |
300 | } | 313 | } |
301 | 314 | ||
302 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 315 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
303 | { | 316 | { |
304 | struct xfrm_state *x; | 317 | struct xfrm_state *x; |
318 | int err; | ||
319 | struct km_event c; | ||
305 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 320 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
306 | 321 | ||
307 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 322 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); |
@@ -313,10 +328,19 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
313 | return -EPERM; | 328 | return -EPERM; |
314 | } | 329 | } |
315 | 330 | ||
316 | xfrm_state_delete(x); | 331 | err = xfrm_state_delete(x); |
332 | if (err < 0) { | ||
333 | xfrm_state_put(x); | ||
334 | return err; | ||
335 | } | ||
336 | |||
337 | c.seq = nlh->nlmsg_seq; | ||
338 | c.pid = nlh->nlmsg_pid; | ||
339 | c.event = XFRM_SAP_DELETED; | ||
340 | km_state_notify(x, &c); | ||
317 | xfrm_state_put(x); | 341 | xfrm_state_put(x); |
318 | 342 | ||
319 | return 0; | 343 | return err; |
320 | } | 344 | } |
321 | 345 | ||
322 | static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 346 | static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
@@ -681,6 +705,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
681 | { | 705 | { |
682 | struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); | 706 | struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); |
683 | struct xfrm_policy *xp; | 707 | struct xfrm_policy *xp; |
708 | struct km_event c; | ||
684 | int err; | 709 | int err; |
685 | int excl; | 710 | int excl; |
686 | 711 | ||
@@ -692,6 +717,10 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
692 | if (!xp) | 717 | if (!xp) |
693 | return err; | 718 | return err; |
694 | 719 | ||
720 | /* shouldnt excl be based on nlh flags?? | ||
721 | * Aha! this is anti-netlink really i.e more pfkey derived | ||
722 | * in netlink excl is a flag and you wouldnt need | ||
723 | * a type XFRM_MSG_UPDPOLICY - JHS */ | ||
695 | excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; | 724 | excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; |
696 | err = xfrm_policy_insert(p->dir, xp, excl); | 725 | err = xfrm_policy_insert(p->dir, xp, excl); |
697 | if (err) { | 726 | if (err) { |
@@ -699,6 +728,15 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
699 | return err; | 728 | return err; |
700 | } | 729 | } |
701 | 730 | ||
731 | if (!excl) | ||
732 | c.event = XFRM_SAP_UPDATED; | ||
733 | else | ||
734 | c.event = XFRM_SAP_ADDED; | ||
735 | |||
736 | c.seq = nlh->nlmsg_seq; | ||
737 | c.pid = nlh->nlmsg_pid; | ||
738 | km_policy_notify(xp, p->dir, &c); | ||
739 | |||
702 | xfrm_pol_put(xp); | 740 | xfrm_pol_put(xp); |
703 | 741 | ||
704 | return 0; | 742 | return 0; |
@@ -816,6 +854,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
816 | struct xfrm_policy *xp; | 854 | struct xfrm_policy *xp; |
817 | struct xfrm_userpolicy_id *p; | 855 | struct xfrm_userpolicy_id *p; |
818 | int err; | 856 | int err; |
857 | struct km_event c; | ||
819 | int delete; | 858 | int delete; |
820 | 859 | ||
821 | p = NLMSG_DATA(nlh); | 860 | p = NLMSG_DATA(nlh); |
@@ -843,6 +882,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
843 | NETLINK_CB(skb).pid, | 882 | NETLINK_CB(skb).pid, |
844 | MSG_DONTWAIT); | 883 | MSG_DONTWAIT); |
845 | } | 884 | } |
885 | } else { | ||
886 | c.event = XFRM_SAP_DELETED; | ||
887 | c.seq = nlh->nlmsg_seq; | ||
888 | c.pid = nlh->nlmsg_pid; | ||
889 | km_policy_notify(xp, p->dir, &c); | ||
846 | } | 890 | } |
847 | 891 | ||
848 | xfrm_pol_put(xp); | 892 | xfrm_pol_put(xp); |
@@ -852,15 +896,28 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
852 | 896 | ||
853 | static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 897 | static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
854 | { | 898 | { |
899 | struct km_event c; | ||
855 | struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); | 900 | struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); |
856 | 901 | ||
857 | xfrm_state_flush(p->proto); | 902 | xfrm_state_flush(p->proto); |
903 | c.data = p->proto; | ||
904 | c.event = XFRM_SAP_FLUSHED; | ||
905 | c.seq = nlh->nlmsg_seq; | ||
906 | c.pid = nlh->nlmsg_pid; | ||
907 | km_state_notify(NULL, &c); | ||
908 | |||
858 | return 0; | 909 | return 0; |
859 | } | 910 | } |
860 | 911 | ||
861 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 912 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
862 | { | 913 | { |
914 | struct km_event c; | ||
915 | |||
863 | xfrm_policy_flush(); | 916 | xfrm_policy_flush(); |
917 | c.event = XFRM_SAP_FLUSHED; | ||
918 | c.seq = nlh->nlmsg_seq; | ||
919 | c.pid = nlh->nlmsg_pid; | ||
920 | km_policy_notify(NULL, 0, &c); | ||
864 | return 0; | 921 | return 0; |
865 | } | 922 | } |
866 | 923 | ||
@@ -1069,10 +1126,12 @@ nlmsg_failure: | |||
1069 | return -1; | 1126 | return -1; |
1070 | } | 1127 | } |
1071 | 1128 | ||
1072 | static int xfrm_send_state_notify(struct xfrm_state *x, int hard) | 1129 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) |
1073 | { | 1130 | { |
1074 | struct sk_buff *skb; | 1131 | struct sk_buff *skb; |
1132 | int hard = c ->data; | ||
1075 | 1133 | ||
1134 | /* fix to do alloc using NLM macros */ | ||
1076 | skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC); | 1135 | skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC); |
1077 | if (skb == NULL) | 1136 | if (skb == NULL) |
1078 | return -ENOMEM; | 1137 | return -ENOMEM; |
@@ -1085,6 +1144,122 @@ static int xfrm_send_state_notify(struct xfrm_state *x, int hard) | |||
1085 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); | 1144 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); |
1086 | } | 1145 | } |
1087 | 1146 | ||
1147 | static int xfrm_notify_sa_flush(struct km_event *c) | ||
1148 | { | ||
1149 | struct xfrm_usersa_flush *p; | ||
1150 | struct nlmsghdr *nlh; | ||
1151 | struct sk_buff *skb; | ||
1152 | unsigned char *b; | ||
1153 | int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); | ||
1154 | |||
1155 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1156 | if (skb == NULL) | ||
1157 | return -ENOMEM; | ||
1158 | b = skb->tail; | ||
1159 | |||
1160 | nlh = NLMSG_PUT(skb, c->pid, c->seq, | ||
1161 | XFRM_MSG_FLUSHSA, sizeof(*p)); | ||
1162 | nlh->nlmsg_flags = 0; | ||
1163 | |||
1164 | p = NLMSG_DATA(nlh); | ||
1165 | p->proto = c->data; | ||
1166 | |||
1167 | nlh->nlmsg_len = skb->tail - b; | ||
1168 | |||
1169 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC); | ||
1170 | |||
1171 | nlmsg_failure: | ||
1172 | kfree_skb(skb); | ||
1173 | return -1; | ||
1174 | } | ||
1175 | |||
1176 | static int inline xfrm_sa_len(struct xfrm_state *x) | ||
1177 | { | ||
1178 | int l = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); | ||
1179 | if (x->aalg) | ||
1180 | l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8); | ||
1181 | if (x->ealg) | ||
1182 | l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8); | ||
1183 | if (x->calg) | ||
1184 | l += RTA_SPACE(sizeof(*x->calg)); | ||
1185 | if (x->encap) | ||
1186 | l += RTA_SPACE(sizeof(*x->encap)); | ||
1187 | |||
1188 | return l; | ||
1189 | } | ||
1190 | |||
1191 | static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) | ||
1192 | { | ||
1193 | struct xfrm_usersa_info *p; | ||
1194 | struct nlmsghdr *nlh; | ||
1195 | struct sk_buff *skb; | ||
1196 | u32 nlt; | ||
1197 | unsigned char *b; | ||
1198 | int len = xfrm_sa_len(x); | ||
1199 | |||
1200 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1201 | if (skb == NULL) | ||
1202 | return -ENOMEM; | ||
1203 | b = skb->tail; | ||
1204 | |||
1205 | if (c->event == XFRM_SAP_ADDED) | ||
1206 | nlt = XFRM_MSG_NEWSA; | ||
1207 | else if (c->event == XFRM_SAP_UPDATED) | ||
1208 | nlt = XFRM_MSG_UPDSA; | ||
1209 | else if (c->event == XFRM_SAP_DELETED) | ||
1210 | nlt = XFRM_MSG_DELSA; | ||
1211 | else | ||
1212 | goto nlmsg_failure; | ||
1213 | |||
1214 | nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p)); | ||
1215 | nlh->nlmsg_flags = 0; | ||
1216 | |||
1217 | p = NLMSG_DATA(nlh); | ||
1218 | copy_to_user_state(x, p); | ||
1219 | |||
1220 | if (x->aalg) | ||
1221 | RTA_PUT(skb, XFRMA_ALG_AUTH, | ||
1222 | sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); | ||
1223 | if (x->ealg) | ||
1224 | RTA_PUT(skb, XFRMA_ALG_CRYPT, | ||
1225 | sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); | ||
1226 | if (x->calg) | ||
1227 | RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); | ||
1228 | |||
1229 | if (x->encap) | ||
1230 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | ||
1231 | |||
1232 | nlh->nlmsg_len = skb->tail - b; | ||
1233 | |||
1234 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC); | ||
1235 | |||
1236 | nlmsg_failure: | ||
1237 | rtattr_failure: | ||
1238 | kfree_skb(skb); | ||
1239 | return -1; | ||
1240 | } | ||
1241 | |||
1242 | static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) | ||
1243 | { | ||
1244 | |||
1245 | switch (c->event) { | ||
1246 | case XFRM_SAP_EXPIRED: | ||
1247 | return xfrm_exp_state_notify(x, c); | ||
1248 | case XFRM_SAP_DELETED: | ||
1249 | case XFRM_SAP_UPDATED: | ||
1250 | case XFRM_SAP_ADDED: | ||
1251 | return xfrm_notify_sa(x, c); | ||
1252 | case XFRM_SAP_FLUSHED: | ||
1253 | return xfrm_notify_sa_flush(c); | ||
1254 | default: | ||
1255 | printk("xfrm_user: Unknown SA event %d\n", c->event); | ||
1256 | break; | ||
1257 | } | ||
1258 | |||
1259 | return 0; | ||
1260 | |||
1261 | } | ||
1262 | |||
1088 | static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | 1263 | static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, |
1089 | struct xfrm_tmpl *xt, struct xfrm_policy *xp, | 1264 | struct xfrm_tmpl *xt, struct xfrm_policy *xp, |
1090 | int dir) | 1265 | int dir) |
@@ -1218,7 +1393,7 @@ nlmsg_failure: | |||
1218 | return -1; | 1393 | return -1; |
1219 | } | 1394 | } |
1220 | 1395 | ||
1221 | static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard) | 1396 | static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) |
1222 | { | 1397 | { |
1223 | struct sk_buff *skb; | 1398 | struct sk_buff *skb; |
1224 | size_t len; | 1399 | size_t len; |
@@ -1229,7 +1404,7 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard) | |||
1229 | if (skb == NULL) | 1404 | if (skb == NULL) |
1230 | return -ENOMEM; | 1405 | return -ENOMEM; |
1231 | 1406 | ||
1232 | if (build_polexpire(skb, xp, dir, hard) < 0) | 1407 | if (build_polexpire(skb, xp, dir, c->data) < 0) |
1233 | BUG(); | 1408 | BUG(); |
1234 | 1409 | ||
1235 | NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE; | 1410 | NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE; |
@@ -1237,6 +1412,93 @@ 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); | 1412 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); |
1238 | } | 1413 | } |
1239 | 1414 | ||
1415 | static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) | ||
1416 | { | ||
1417 | struct xfrm_userpolicy_info *p; | ||
1418 | struct nlmsghdr *nlh; | ||
1419 | struct sk_buff *skb; | ||
1420 | u32 nlt = 0 ; | ||
1421 | unsigned char *b; | ||
1422 | int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | ||
1423 | len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_info)); | ||
1424 | |||
1425 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1426 | if (skb == NULL) | ||
1427 | return -ENOMEM; | ||
1428 | b = skb->tail; | ||
1429 | |||
1430 | if (c->event == XFRM_SAP_ADDED) | ||
1431 | nlt = XFRM_MSG_NEWPOLICY; | ||
1432 | else if (c->event == XFRM_SAP_UPDATED) | ||
1433 | nlt = XFRM_MSG_UPDPOLICY; | ||
1434 | else if (c->event == XFRM_SAP_DELETED) | ||
1435 | nlt = XFRM_MSG_DELPOLICY; | ||
1436 | else | ||
1437 | goto nlmsg_failure; | ||
1438 | |||
1439 | nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p)); | ||
1440 | |||
1441 | p = NLMSG_DATA(nlh); | ||
1442 | |||
1443 | nlh->nlmsg_flags = 0; | ||
1444 | |||
1445 | copy_to_user_policy(xp, p, dir); | ||
1446 | if (copy_to_user_tmpl(xp, skb) < 0) | ||
1447 | goto nlmsg_failure; | ||
1448 | |||
1449 | nlh->nlmsg_len = skb->tail - b; | ||
1450 | |||
1451 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC); | ||
1452 | |||
1453 | nlmsg_failure: | ||
1454 | kfree_skb(skb); | ||
1455 | return -1; | ||
1456 | } | ||
1457 | |||
1458 | static int xfrm_notify_policy_flush(struct km_event *c) | ||
1459 | { | ||
1460 | struct nlmsghdr *nlh; | ||
1461 | struct sk_buff *skb; | ||
1462 | unsigned char *b; | ||
1463 | int len = NLMSG_LENGTH(0); | ||
1464 | |||
1465 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1466 | if (skb == NULL) | ||
1467 | return -ENOMEM; | ||
1468 | b = skb->tail; | ||
1469 | |||
1470 | |||
1471 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); | ||
1472 | |||
1473 | nlh->nlmsg_len = skb->tail - b; | ||
1474 | |||
1475 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC); | ||
1476 | |||
1477 | nlmsg_failure: | ||
1478 | kfree_skb(skb); | ||
1479 | return -1; | ||
1480 | } | ||
1481 | |||
1482 | static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) | ||
1483 | { | ||
1484 | |||
1485 | switch (c->event) { | ||
1486 | case XFRM_SAP_ADDED: | ||
1487 | case XFRM_SAP_UPDATED: | ||
1488 | case XFRM_SAP_DELETED: | ||
1489 | return xfrm_notify_policy(xp, dir, c); | ||
1490 | case XFRM_SAP_FLUSHED: | ||
1491 | return xfrm_notify_policy_flush(c); | ||
1492 | case XFRM_SAP_EXPIRED: | ||
1493 | return xfrm_exp_policy_notify(xp, dir, c); | ||
1494 | default: | ||
1495 | printk("xfrm_user: Unknown Policy event %d\n", c->event); | ||
1496 | } | ||
1497 | |||
1498 | return 0; | ||
1499 | |||
1500 | } | ||
1501 | |||
1240 | static struct xfrm_mgr netlink_mgr = { | 1502 | static struct xfrm_mgr netlink_mgr = { |
1241 | .id = "netlink", | 1503 | .id = "netlink", |
1242 | .notify = xfrm_send_state_notify, | 1504 | .notify = xfrm_send_state_notify, |