diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-09-24 01:52:47 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-24 01:52:47 -0400 |
commit | 23930fa1cebfea6f79881c588ccd1b0781e49e3f (patch) | |
tree | 36d29e3f83661c4f5f45b6f74ac0d5f9886867a8 /net/xfrm | |
parent | 36b35a5be0e4b406acd816e2122d153e875105be (diff) | |
parent | 4f5537de7c1531398e84e18a24f667e49cc94208 (diff) |
Merge branch 'master' into upstream
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/Kconfig | 16 | ||||
-rw-r--r-- | net/xfrm/Makefile | 3 | ||||
-rw-r--r-- | net/xfrm/xfrm_algo.c | 94 | ||||
-rw-r--r-- | net/xfrm/xfrm_hash.c | 41 | ||||
-rw-r--r-- | net/xfrm/xfrm_hash.h | 128 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 4 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 901 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 640 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 350 |
9 files changed, 1786 insertions, 391 deletions
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index 0c1c04322baf..0faab6332586 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig | |||
@@ -6,14 +6,24 @@ config XFRM | |||
6 | depends on NET | 6 | depends on NET |
7 | 7 | ||
8 | config XFRM_USER | 8 | config XFRM_USER |
9 | tristate "IPsec user configuration interface" | 9 | tristate "Transformation user configuration interface" |
10 | depends on INET && XFRM | 10 | depends on INET && XFRM |
11 | ---help--- | 11 | ---help--- |
12 | Support for IPsec user configuration interface used | 12 | Support for Transformation(XFRM) user configuration interface |
13 | by native Linux tools. | 13 | like IPsec used by native Linux tools. |
14 | 14 | ||
15 | If unsure, say Y. | 15 | If unsure, say Y. |
16 | 16 | ||
17 | config XFRM_SUB_POLICY | ||
18 | bool "Transformation sub policy support (EXPERIMENTAL)" | ||
19 | depends on XFRM && EXPERIMENTAL | ||
20 | ---help--- | ||
21 | Support sub policy for developers. By using sub policy with main | ||
22 | one, two policies can be applied to the same packet at once. | ||
23 | Policy which lives shorter time in kernel should be a sub. | ||
24 | |||
25 | If unsure, say N. | ||
26 | |||
17 | config NET_KEY | 27 | config NET_KEY |
18 | tristate "PF_KEY sockets" | 28 | tristate "PF_KEY sockets" |
19 | select XFRM | 29 | select XFRM |
diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index 693aac1aa833..de3c1a625a46 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile | |||
@@ -2,6 +2,7 @@ | |||
2 | # Makefile for the XFRM subsystem. | 2 | # Makefile for the XFRM subsystem. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o | 5 | obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ |
6 | xfrm_input.o xfrm_algo.o | ||
6 | obj-$(CONFIG_XFRM_USER) += xfrm_user.o | 7 | obj-$(CONFIG_XFRM_USER) += xfrm_user.o |
7 | 8 | ||
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 04e1aea58bc9..5a0dbeb6bbe8 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c | |||
@@ -30,7 +30,8 @@ | |||
30 | */ | 30 | */ |
31 | static struct xfrm_algo_desc aalg_list[] = { | 31 | static struct xfrm_algo_desc aalg_list[] = { |
32 | { | 32 | { |
33 | .name = "digest_null", | 33 | .name = "hmac(digest_null)", |
34 | .compat = "digest_null", | ||
34 | 35 | ||
35 | .uinfo = { | 36 | .uinfo = { |
36 | .auth = { | 37 | .auth = { |
@@ -47,7 +48,8 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
47 | } | 48 | } |
48 | }, | 49 | }, |
49 | { | 50 | { |
50 | .name = "md5", | 51 | .name = "hmac(md5)", |
52 | .compat = "md5", | ||
51 | 53 | ||
52 | .uinfo = { | 54 | .uinfo = { |
53 | .auth = { | 55 | .auth = { |
@@ -64,7 +66,8 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
64 | } | 66 | } |
65 | }, | 67 | }, |
66 | { | 68 | { |
67 | .name = "sha1", | 69 | .name = "hmac(sha1)", |
70 | .compat = "sha1", | ||
68 | 71 | ||
69 | .uinfo = { | 72 | .uinfo = { |
70 | .auth = { | 73 | .auth = { |
@@ -81,7 +84,8 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
81 | } | 84 | } |
82 | }, | 85 | }, |
83 | { | 86 | { |
84 | .name = "sha256", | 87 | .name = "hmac(sha256)", |
88 | .compat = "sha256", | ||
85 | 89 | ||
86 | .uinfo = { | 90 | .uinfo = { |
87 | .auth = { | 91 | .auth = { |
@@ -98,7 +102,8 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
98 | } | 102 | } |
99 | }, | 103 | }, |
100 | { | 104 | { |
101 | .name = "ripemd160", | 105 | .name = "hmac(ripemd160)", |
106 | .compat = "ripemd160", | ||
102 | 107 | ||
103 | .uinfo = { | 108 | .uinfo = { |
104 | .auth = { | 109 | .auth = { |
@@ -118,7 +123,8 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
118 | 123 | ||
119 | static struct xfrm_algo_desc ealg_list[] = { | 124 | static struct xfrm_algo_desc ealg_list[] = { |
120 | { | 125 | { |
121 | .name = "cipher_null", | 126 | .name = "ecb(cipher_null)", |
127 | .compat = "cipher_null", | ||
122 | 128 | ||
123 | .uinfo = { | 129 | .uinfo = { |
124 | .encr = { | 130 | .encr = { |
@@ -135,7 +141,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
135 | } | 141 | } |
136 | }, | 142 | }, |
137 | { | 143 | { |
138 | .name = "des", | 144 | .name = "cbc(des)", |
145 | .compat = "des", | ||
139 | 146 | ||
140 | .uinfo = { | 147 | .uinfo = { |
141 | .encr = { | 148 | .encr = { |
@@ -152,7 +159,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
152 | } | 159 | } |
153 | }, | 160 | }, |
154 | { | 161 | { |
155 | .name = "des3_ede", | 162 | .name = "cbc(des3_ede)", |
163 | .compat = "des3_ede", | ||
156 | 164 | ||
157 | .uinfo = { | 165 | .uinfo = { |
158 | .encr = { | 166 | .encr = { |
@@ -169,7 +177,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
169 | } | 177 | } |
170 | }, | 178 | }, |
171 | { | 179 | { |
172 | .name = "cast128", | 180 | .name = "cbc(cast128)", |
181 | .compat = "cast128", | ||
173 | 182 | ||
174 | .uinfo = { | 183 | .uinfo = { |
175 | .encr = { | 184 | .encr = { |
@@ -186,7 +195,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
186 | } | 195 | } |
187 | }, | 196 | }, |
188 | { | 197 | { |
189 | .name = "blowfish", | 198 | .name = "cbc(blowfish)", |
199 | .compat = "blowfish", | ||
190 | 200 | ||
191 | .uinfo = { | 201 | .uinfo = { |
192 | .encr = { | 202 | .encr = { |
@@ -203,7 +213,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
203 | } | 213 | } |
204 | }, | 214 | }, |
205 | { | 215 | { |
206 | .name = "aes", | 216 | .name = "cbc(aes)", |
217 | .compat = "aes", | ||
207 | 218 | ||
208 | .uinfo = { | 219 | .uinfo = { |
209 | .encr = { | 220 | .encr = { |
@@ -220,7 +231,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
220 | } | 231 | } |
221 | }, | 232 | }, |
222 | { | 233 | { |
223 | .name = "serpent", | 234 | .name = "cbc(serpent)", |
235 | .compat = "serpent", | ||
224 | 236 | ||
225 | .uinfo = { | 237 | .uinfo = { |
226 | .encr = { | 238 | .encr = { |
@@ -237,7 +249,8 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
237 | } | 249 | } |
238 | }, | 250 | }, |
239 | { | 251 | { |
240 | .name = "twofish", | 252 | .name = "cbc(twofish)", |
253 | .compat = "twofish", | ||
241 | 254 | ||
242 | .uinfo = { | 255 | .uinfo = { |
243 | .encr = { | 256 | .encr = { |
@@ -350,8 +363,8 @@ struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id) | |||
350 | EXPORT_SYMBOL_GPL(xfrm_calg_get_byid); | 363 | EXPORT_SYMBOL_GPL(xfrm_calg_get_byid); |
351 | 364 | ||
352 | static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list, | 365 | static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list, |
353 | int entries, char *name, | 366 | int entries, u32 type, u32 mask, |
354 | int probe) | 367 | char *name, int probe) |
355 | { | 368 | { |
356 | int i, status; | 369 | int i, status; |
357 | 370 | ||
@@ -359,7 +372,8 @@ static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list, | |||
359 | return NULL; | 372 | return NULL; |
360 | 373 | ||
361 | for (i = 0; i < entries; i++) { | 374 | for (i = 0; i < entries; i++) { |
362 | if (strcmp(name, list[i].name)) | 375 | if (strcmp(name, list[i].name) && |
376 | (!list[i].compat || strcmp(name, list[i].compat))) | ||
363 | continue; | 377 | continue; |
364 | 378 | ||
365 | if (list[i].available) | 379 | if (list[i].available) |
@@ -368,7 +382,7 @@ static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list, | |||
368 | if (!probe) | 382 | if (!probe) |
369 | break; | 383 | break; |
370 | 384 | ||
371 | status = crypto_alg_available(name, 0); | 385 | status = crypto_has_alg(name, type, mask | CRYPTO_ALG_ASYNC); |
372 | if (!status) | 386 | if (!status) |
373 | break; | 387 | break; |
374 | 388 | ||
@@ -380,19 +394,25 @@ static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list, | |||
380 | 394 | ||
381 | struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe) | 395 | struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe) |
382 | { | 396 | { |
383 | return xfrm_get_byname(aalg_list, aalg_entries(), name, probe); | 397 | return xfrm_get_byname(aalg_list, aalg_entries(), |
398 | CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_HASH_MASK, | ||
399 | name, probe); | ||
384 | } | 400 | } |
385 | EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname); | 401 | EXPORT_SYMBOL_GPL(xfrm_aalg_get_byname); |
386 | 402 | ||
387 | struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe) | 403 | struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe) |
388 | { | 404 | { |
389 | return xfrm_get_byname(ealg_list, ealg_entries(), name, probe); | 405 | return xfrm_get_byname(ealg_list, ealg_entries(), |
406 | CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_MASK, | ||
407 | name, probe); | ||
390 | } | 408 | } |
391 | EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname); | 409 | EXPORT_SYMBOL_GPL(xfrm_ealg_get_byname); |
392 | 410 | ||
393 | struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe) | 411 | struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe) |
394 | { | 412 | { |
395 | return xfrm_get_byname(calg_list, calg_entries(), name, probe); | 413 | return xfrm_get_byname(calg_list, calg_entries(), |
414 | CRYPTO_ALG_TYPE_COMPRESS, CRYPTO_ALG_TYPE_MASK, | ||
415 | name, probe); | ||
396 | } | 416 | } |
397 | EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); | 417 | EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); |
398 | 418 | ||
@@ -427,19 +447,22 @@ void xfrm_probe_algs(void) | |||
427 | BUG_ON(in_softirq()); | 447 | BUG_ON(in_softirq()); |
428 | 448 | ||
429 | for (i = 0; i < aalg_entries(); i++) { | 449 | for (i = 0; i < aalg_entries(); i++) { |
430 | status = crypto_alg_available(aalg_list[i].name, 0); | 450 | status = crypto_has_hash(aalg_list[i].name, 0, |
451 | CRYPTO_ALG_ASYNC); | ||
431 | if (aalg_list[i].available != status) | 452 | if (aalg_list[i].available != status) |
432 | aalg_list[i].available = status; | 453 | aalg_list[i].available = status; |
433 | } | 454 | } |
434 | 455 | ||
435 | for (i = 0; i < ealg_entries(); i++) { | 456 | for (i = 0; i < ealg_entries(); i++) { |
436 | status = crypto_alg_available(ealg_list[i].name, 0); | 457 | status = crypto_has_blkcipher(ealg_list[i].name, 0, |
458 | CRYPTO_ALG_ASYNC); | ||
437 | if (ealg_list[i].available != status) | 459 | if (ealg_list[i].available != status) |
438 | ealg_list[i].available = status; | 460 | ealg_list[i].available = status; |
439 | } | 461 | } |
440 | 462 | ||
441 | for (i = 0; i < calg_entries(); i++) { | 463 | for (i = 0; i < calg_entries(); i++) { |
442 | status = crypto_alg_available(calg_list[i].name, 0); | 464 | status = crypto_has_comp(calg_list[i].name, 0, |
465 | CRYPTO_ALG_ASYNC); | ||
443 | if (calg_list[i].available != status) | 466 | if (calg_list[i].available != status) |
444 | calg_list[i].available = status; | 467 | calg_list[i].available = status; |
445 | } | 468 | } |
@@ -471,11 +494,12 @@ EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); | |||
471 | 494 | ||
472 | /* Move to common area: it is shared with AH. */ | 495 | /* Move to common area: it is shared with AH. */ |
473 | 496 | ||
474 | void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, | 497 | int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, |
475 | int offset, int len, icv_update_fn_t icv_update) | 498 | int offset, int len, icv_update_fn_t icv_update) |
476 | { | 499 | { |
477 | int start = skb_headlen(skb); | 500 | int start = skb_headlen(skb); |
478 | int i, copy = start - offset; | 501 | int i, copy = start - offset; |
502 | int err; | ||
479 | struct scatterlist sg; | 503 | struct scatterlist sg; |
480 | 504 | ||
481 | /* Checksum header. */ | 505 | /* Checksum header. */ |
@@ -487,10 +511,12 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, | |||
487 | sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE; | 511 | sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE; |
488 | sg.length = copy; | 512 | sg.length = copy; |
489 | 513 | ||
490 | icv_update(tfm, &sg, 1); | 514 | err = icv_update(desc, &sg, copy); |
515 | if (unlikely(err)) | ||
516 | return err; | ||
491 | 517 | ||
492 | if ((len -= copy) == 0) | 518 | if ((len -= copy) == 0) |
493 | return; | 519 | return 0; |
494 | offset += copy; | 520 | offset += copy; |
495 | } | 521 | } |
496 | 522 | ||
@@ -510,10 +536,12 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, | |||
510 | sg.offset = frag->page_offset + offset-start; | 536 | sg.offset = frag->page_offset + offset-start; |
511 | sg.length = copy; | 537 | sg.length = copy; |
512 | 538 | ||
513 | icv_update(tfm, &sg, 1); | 539 | err = icv_update(desc, &sg, copy); |
540 | if (unlikely(err)) | ||
541 | return err; | ||
514 | 542 | ||
515 | if (!(len -= copy)) | 543 | if (!(len -= copy)) |
516 | return; | 544 | return 0; |
517 | offset += copy; | 545 | offset += copy; |
518 | } | 546 | } |
519 | start = end; | 547 | start = end; |
@@ -531,15 +559,19 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, | |||
531 | if ((copy = end - offset) > 0) { | 559 | if ((copy = end - offset) > 0) { |
532 | if (copy > len) | 560 | if (copy > len) |
533 | copy = len; | 561 | copy = len; |
534 | skb_icv_walk(list, tfm, offset-start, copy, icv_update); | 562 | err = skb_icv_walk(list, desc, offset-start, |
563 | copy, icv_update); | ||
564 | if (unlikely(err)) | ||
565 | return err; | ||
535 | if ((len -= copy) == 0) | 566 | if ((len -= copy) == 0) |
536 | return; | 567 | return 0; |
537 | offset += copy; | 568 | offset += copy; |
538 | } | 569 | } |
539 | start = end; | 570 | start = end; |
540 | } | 571 | } |
541 | } | 572 | } |
542 | BUG_ON(len); | 573 | BUG_ON(len); |
574 | return 0; | ||
543 | } | 575 | } |
544 | EXPORT_SYMBOL_GPL(skb_icv_walk); | 576 | EXPORT_SYMBOL_GPL(skb_icv_walk); |
545 | 577 | ||
diff --git a/net/xfrm/xfrm_hash.c b/net/xfrm/xfrm_hash.c new file mode 100644 index 000000000000..37643bb8768a --- /dev/null +++ b/net/xfrm/xfrm_hash.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* xfrm_hash.c: Common hash table code. | ||
2 | * | ||
3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
4 | */ | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/mm.h> | ||
8 | #include <linux/bootmem.h> | ||
9 | #include <linux/vmalloc.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <linux/xfrm.h> | ||
12 | |||
13 | #include "xfrm_hash.h" | ||
14 | |||
15 | struct hlist_head *xfrm_hash_alloc(unsigned int sz) | ||
16 | { | ||
17 | struct hlist_head *n; | ||
18 | |||
19 | if (sz <= PAGE_SIZE) | ||
20 | n = kmalloc(sz, GFP_KERNEL); | ||
21 | else if (hashdist) | ||
22 | n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL); | ||
23 | else | ||
24 | n = (struct hlist_head *) | ||
25 | __get_free_pages(GFP_KERNEL, get_order(sz)); | ||
26 | |||
27 | if (n) | ||
28 | memset(n, 0, sz); | ||
29 | |||
30 | return n; | ||
31 | } | ||
32 | |||
33 | void xfrm_hash_free(struct hlist_head *n, unsigned int sz) | ||
34 | { | ||
35 | if (sz <= PAGE_SIZE) | ||
36 | kfree(n); | ||
37 | else if (hashdist) | ||
38 | vfree(n); | ||
39 | else | ||
40 | free_pages((unsigned long)n, get_order(sz)); | ||
41 | } | ||
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h new file mode 100644 index 000000000000..d3abb0b7dc62 --- /dev/null +++ b/net/xfrm/xfrm_hash.h | |||
@@ -0,0 +1,128 @@ | |||
1 | #ifndef _XFRM_HASH_H | ||
2 | #define _XFRM_HASH_H | ||
3 | |||
4 | #include <linux/xfrm.h> | ||
5 | #include <linux/socket.h> | ||
6 | |||
7 | static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr) | ||
8 | { | ||
9 | return ntohl(addr->a4); | ||
10 | } | ||
11 | |||
12 | static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr) | ||
13 | { | ||
14 | return ntohl(addr->a6[2] ^ addr->a6[3]); | ||
15 | } | ||
16 | |||
17 | static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
18 | { | ||
19 | return ntohl(daddr->a4 ^ saddr->a4); | ||
20 | } | ||
21 | |||
22 | static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
23 | { | ||
24 | return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | ||
25 | saddr->a6[2] ^ saddr->a6[3]); | ||
26 | } | ||
27 | |||
28 | static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
29 | u32 reqid, unsigned short family, | ||
30 | unsigned int hmask) | ||
31 | { | ||
32 | unsigned int h = family ^ reqid; | ||
33 | switch (family) { | ||
34 | case AF_INET: | ||
35 | h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
36 | break; | ||
37 | case AF_INET6: | ||
38 | h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
39 | break; | ||
40 | } | ||
41 | return (h ^ (h >> 16)) & hmask; | ||
42 | } | ||
43 | |||
44 | static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr, | ||
45 | unsigned short family, | ||
46 | unsigned int hmask) | ||
47 | { | ||
48 | unsigned int h = family; | ||
49 | switch (family) { | ||
50 | case AF_INET: | ||
51 | h ^= __xfrm4_addr_hash(saddr); | ||
52 | break; | ||
53 | case AF_INET6: | ||
54 | h ^= __xfrm6_addr_hash(saddr); | ||
55 | break; | ||
56 | }; | ||
57 | return (h ^ (h >> 16)) & hmask; | ||
58 | } | ||
59 | |||
60 | static inline unsigned int | ||
61 | __xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family, | ||
62 | unsigned int hmask) | ||
63 | { | ||
64 | unsigned int h = spi ^ proto; | ||
65 | switch (family) { | ||
66 | case AF_INET: | ||
67 | h ^= __xfrm4_addr_hash(daddr); | ||
68 | break; | ||
69 | case AF_INET6: | ||
70 | h ^= __xfrm6_addr_hash(daddr); | ||
71 | break; | ||
72 | } | ||
73 | return (h ^ (h >> 10) ^ (h >> 20)) & hmask; | ||
74 | } | ||
75 | |||
76 | static inline unsigned int __idx_hash(u32 index, unsigned int hmask) | ||
77 | { | ||
78 | return (index ^ (index >> 8)) & hmask; | ||
79 | } | ||
80 | |||
81 | static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask) | ||
82 | { | ||
83 | xfrm_address_t *daddr = &sel->daddr; | ||
84 | xfrm_address_t *saddr = &sel->saddr; | ||
85 | unsigned int h = 0; | ||
86 | |||
87 | switch (family) { | ||
88 | case AF_INET: | ||
89 | if (sel->prefixlen_d != 32 || | ||
90 | sel->prefixlen_s != 32) | ||
91 | return hmask + 1; | ||
92 | |||
93 | h = __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
94 | break; | ||
95 | |||
96 | case AF_INET6: | ||
97 | if (sel->prefixlen_d != 128 || | ||
98 | sel->prefixlen_s != 128) | ||
99 | return hmask + 1; | ||
100 | |||
101 | h = __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
102 | break; | ||
103 | }; | ||
104 | h ^= (h >> 16); | ||
105 | return h & hmask; | ||
106 | } | ||
107 | |||
108 | static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask) | ||
109 | { | ||
110 | unsigned int h = 0; | ||
111 | |||
112 | switch (family) { | ||
113 | case AF_INET: | ||
114 | h = __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
115 | break; | ||
116 | |||
117 | case AF_INET6: | ||
118 | h = __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
119 | break; | ||
120 | }; | ||
121 | h ^= (h >> 16); | ||
122 | return h & hmask; | ||
123 | } | ||
124 | |||
125 | extern struct hlist_head *xfrm_hash_alloc(unsigned int sz); | ||
126 | extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz); | ||
127 | |||
128 | #endif /* _XFRM_HASH_H */ | ||
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 891a6090cc09..dfc90bb1cf1f 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -82,8 +82,6 @@ void __init xfrm_input_init(void) | |||
82 | { | 82 | { |
83 | secpath_cachep = kmem_cache_create("secpath_cache", | 83 | secpath_cachep = kmem_cache_create("secpath_cache", |
84 | sizeof(struct sec_path), | 84 | sizeof(struct sec_path), |
85 | 0, SLAB_HWCACHE_ALIGN, | 85 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
86 | NULL, NULL); | 86 | NULL, NULL); |
87 | if (!secpath_cachep) | ||
88 | panic("XFRM: failed to allocate secpath_cache\n"); | ||
89 | } | 87 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3da67ca2c3ce..b6e2e79d7261 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -22,16 +22,19 @@ | |||
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/cache.h> | ||
25 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
26 | #include <net/ip.h> | 27 | #include <net/ip.h> |
27 | 28 | ||
29 | #include "xfrm_hash.h" | ||
30 | |||
28 | DEFINE_MUTEX(xfrm_cfg_mutex); | 31 | DEFINE_MUTEX(xfrm_cfg_mutex); |
29 | EXPORT_SYMBOL(xfrm_cfg_mutex); | 32 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
30 | 33 | ||
31 | static DEFINE_RWLOCK(xfrm_policy_lock); | 34 | static DEFINE_RWLOCK(xfrm_policy_lock); |
32 | 35 | ||
33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | 36 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
34 | EXPORT_SYMBOL(xfrm_policy_list); | 37 | EXPORT_SYMBOL(xfrm_policy_count); |
35 | 38 | ||
36 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | 39 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); |
37 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | 40 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; |
@@ -39,8 +42,7 @@ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | |||
39 | static kmem_cache_t *xfrm_dst_cache __read_mostly; | 42 | static kmem_cache_t *xfrm_dst_cache __read_mostly; |
40 | 43 | ||
41 | static struct work_struct xfrm_policy_gc_work; | 44 | static struct work_struct xfrm_policy_gc_work; |
42 | static struct list_head xfrm_policy_gc_list = | 45 | static HLIST_HEAD(xfrm_policy_gc_list); |
43 | LIST_HEAD_INIT(xfrm_policy_gc_list); | ||
44 | static DEFINE_SPINLOCK(xfrm_policy_gc_lock); | 46 | static DEFINE_SPINLOCK(xfrm_policy_gc_lock); |
45 | 47 | ||
46 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | 48 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); |
@@ -310,8 +312,10 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) | |||
310 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); | 312 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
311 | 313 | ||
312 | if (policy) { | 314 | if (policy) { |
313 | atomic_set(&policy->refcnt, 1); | 315 | INIT_HLIST_NODE(&policy->bydst); |
316 | INIT_HLIST_NODE(&policy->byidx); | ||
314 | rwlock_init(&policy->lock); | 317 | rwlock_init(&policy->lock); |
318 | atomic_set(&policy->refcnt, 1); | ||
315 | init_timer(&policy->timer); | 319 | init_timer(&policy->timer); |
316 | policy->timer.data = (unsigned long)policy; | 320 | policy->timer.data = (unsigned long)policy; |
317 | policy->timer.function = xfrm_policy_timer; | 321 | policy->timer.function = xfrm_policy_timer; |
@@ -357,17 +361,16 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy) | |||
357 | static void xfrm_policy_gc_task(void *data) | 361 | static void xfrm_policy_gc_task(void *data) |
358 | { | 362 | { |
359 | struct xfrm_policy *policy; | 363 | struct xfrm_policy *policy; |
360 | struct list_head *entry, *tmp; | 364 | struct hlist_node *entry, *tmp; |
361 | struct list_head gc_list = LIST_HEAD_INIT(gc_list); | 365 | struct hlist_head gc_list; |
362 | 366 | ||
363 | spin_lock_bh(&xfrm_policy_gc_lock); | 367 | spin_lock_bh(&xfrm_policy_gc_lock); |
364 | list_splice_init(&xfrm_policy_gc_list, &gc_list); | 368 | gc_list.first = xfrm_policy_gc_list.first; |
369 | INIT_HLIST_HEAD(&xfrm_policy_gc_list); | ||
365 | spin_unlock_bh(&xfrm_policy_gc_lock); | 370 | spin_unlock_bh(&xfrm_policy_gc_lock); |
366 | 371 | ||
367 | list_for_each_safe(entry, tmp, &gc_list) { | 372 | hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst) |
368 | policy = list_entry(entry, struct xfrm_policy, list); | ||
369 | xfrm_policy_gc_kill(policy); | 373 | xfrm_policy_gc_kill(policy); |
370 | } | ||
371 | } | 374 | } |
372 | 375 | ||
373 | /* Rule must be locked. Release descentant resources, announce | 376 | /* Rule must be locked. Release descentant resources, announce |
@@ -389,70 +392,275 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
389 | } | 392 | } |
390 | 393 | ||
391 | spin_lock(&xfrm_policy_gc_lock); | 394 | spin_lock(&xfrm_policy_gc_lock); |
392 | list_add(&policy->list, &xfrm_policy_gc_list); | 395 | hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); |
393 | spin_unlock(&xfrm_policy_gc_lock); | 396 | spin_unlock(&xfrm_policy_gc_lock); |
394 | 397 | ||
395 | schedule_work(&xfrm_policy_gc_work); | 398 | schedule_work(&xfrm_policy_gc_work); |
396 | } | 399 | } |
397 | 400 | ||
401 | struct xfrm_policy_hash { | ||
402 | struct hlist_head *table; | ||
403 | unsigned int hmask; | ||
404 | }; | ||
405 | |||
406 | static struct hlist_head xfrm_policy_inexact[XFRM_POLICY_MAX*2]; | ||
407 | static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly; | ||
408 | static struct hlist_head *xfrm_policy_byidx __read_mostly; | ||
409 | static unsigned int xfrm_idx_hmask __read_mostly; | ||
410 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; | ||
411 | |||
412 | static inline unsigned int idx_hash(u32 index) | ||
413 | { | ||
414 | return __idx_hash(index, xfrm_idx_hmask); | ||
415 | } | ||
416 | |||
417 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) | ||
418 | { | ||
419 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
420 | unsigned int hash = __sel_hash(sel, family, hmask); | ||
421 | |||
422 | return (hash == hmask + 1 ? | ||
423 | &xfrm_policy_inexact[dir] : | ||
424 | xfrm_policy_bydst[dir].table + hash); | ||
425 | } | ||
426 | |||
427 | static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) | ||
428 | { | ||
429 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
430 | unsigned int hash = __addr_hash(daddr, saddr, family, hmask); | ||
431 | |||
432 | return xfrm_policy_bydst[dir].table + hash; | ||
433 | } | ||
434 | |||
435 | static void xfrm_dst_hash_transfer(struct hlist_head *list, | ||
436 | struct hlist_head *ndsttable, | ||
437 | unsigned int nhashmask) | ||
438 | { | ||
439 | struct hlist_node *entry, *tmp; | ||
440 | struct xfrm_policy *pol; | ||
441 | |||
442 | hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) { | ||
443 | unsigned int h; | ||
444 | |||
445 | h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, | ||
446 | pol->family, nhashmask); | ||
447 | hlist_add_head(&pol->bydst, ndsttable+h); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void xfrm_idx_hash_transfer(struct hlist_head *list, | ||
452 | struct hlist_head *nidxtable, | ||
453 | unsigned int nhashmask) | ||
454 | { | ||
455 | struct hlist_node *entry, *tmp; | ||
456 | struct xfrm_policy *pol; | ||
457 | |||
458 | hlist_for_each_entry_safe(pol, entry, tmp, list, byidx) { | ||
459 | unsigned int h; | ||
460 | |||
461 | h = __idx_hash(pol->index, nhashmask); | ||
462 | hlist_add_head(&pol->byidx, nidxtable+h); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) | ||
467 | { | ||
468 | return ((old_hmask + 1) << 1) - 1; | ||
469 | } | ||
470 | |||
471 | static void xfrm_bydst_resize(int dir) | ||
472 | { | ||
473 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
474 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | ||
475 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | ||
476 | struct hlist_head *odst = xfrm_policy_bydst[dir].table; | ||
477 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); | ||
478 | int i; | ||
479 | |||
480 | if (!ndst) | ||
481 | return; | ||
482 | |||
483 | write_lock_bh(&xfrm_policy_lock); | ||
484 | |||
485 | for (i = hmask; i >= 0; i--) | ||
486 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); | ||
487 | |||
488 | xfrm_policy_bydst[dir].table = ndst; | ||
489 | xfrm_policy_bydst[dir].hmask = nhashmask; | ||
490 | |||
491 | write_unlock_bh(&xfrm_policy_lock); | ||
492 | |||
493 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); | ||
494 | } | ||
495 | |||
496 | static void xfrm_byidx_resize(int total) | ||
497 | { | ||
498 | unsigned int hmask = xfrm_idx_hmask; | ||
499 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | ||
500 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | ||
501 | struct hlist_head *oidx = xfrm_policy_byidx; | ||
502 | struct hlist_head *nidx = xfrm_hash_alloc(nsize); | ||
503 | int i; | ||
504 | |||
505 | if (!nidx) | ||
506 | return; | ||
507 | |||
508 | write_lock_bh(&xfrm_policy_lock); | ||
509 | |||
510 | for (i = hmask; i >= 0; i--) | ||
511 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); | ||
512 | |||
513 | xfrm_policy_byidx = nidx; | ||
514 | xfrm_idx_hmask = nhashmask; | ||
515 | |||
516 | write_unlock_bh(&xfrm_policy_lock); | ||
517 | |||
518 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); | ||
519 | } | ||
520 | |||
521 | static inline int xfrm_bydst_should_resize(int dir, int *total) | ||
522 | { | ||
523 | unsigned int cnt = xfrm_policy_count[dir]; | ||
524 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
525 | |||
526 | if (total) | ||
527 | *total += cnt; | ||
528 | |||
529 | if ((hmask + 1) < xfrm_policy_hashmax && | ||
530 | cnt > hmask) | ||
531 | return 1; | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static inline int xfrm_byidx_should_resize(int total) | ||
537 | { | ||
538 | unsigned int hmask = xfrm_idx_hmask; | ||
539 | |||
540 | if ((hmask + 1) < xfrm_policy_hashmax && | ||
541 | total > hmask) | ||
542 | return 1; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static DEFINE_MUTEX(hash_resize_mutex); | ||
548 | |||
549 | static void xfrm_hash_resize(void *__unused) | ||
550 | { | ||
551 | int dir, total; | ||
552 | |||
553 | mutex_lock(&hash_resize_mutex); | ||
554 | |||
555 | total = 0; | ||
556 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
557 | if (xfrm_bydst_should_resize(dir, &total)) | ||
558 | xfrm_bydst_resize(dir); | ||
559 | } | ||
560 | if (xfrm_byidx_should_resize(total)) | ||
561 | xfrm_byidx_resize(total); | ||
562 | |||
563 | mutex_unlock(&hash_resize_mutex); | ||
564 | } | ||
565 | |||
566 | static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); | ||
567 | |||
398 | /* Generate new index... KAME seems to generate them ordered by cost | 568 | /* Generate new index... KAME seems to generate them ordered by cost |
399 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 569 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
400 | static u32 xfrm_gen_index(int dir) | 570 | static u32 xfrm_gen_index(u8 type, int dir) |
401 | { | 571 | { |
402 | u32 idx; | ||
403 | struct xfrm_policy *p; | ||
404 | static u32 idx_generator; | 572 | static u32 idx_generator; |
405 | 573 | ||
406 | for (;;) { | 574 | for (;;) { |
575 | struct hlist_node *entry; | ||
576 | struct hlist_head *list; | ||
577 | struct xfrm_policy *p; | ||
578 | u32 idx; | ||
579 | int found; | ||
580 | |||
407 | idx = (idx_generator | dir); | 581 | idx = (idx_generator | dir); |
408 | idx_generator += 8; | 582 | idx_generator += 8; |
409 | if (idx == 0) | 583 | if (idx == 0) |
410 | idx = 8; | 584 | idx = 8; |
411 | for (p = xfrm_policy_list[dir]; p; p = p->next) { | 585 | list = xfrm_policy_byidx + idx_hash(idx); |
412 | if (p->index == idx) | 586 | found = 0; |
587 | hlist_for_each_entry(p, entry, list, byidx) { | ||
588 | if (p->index == idx) { | ||
589 | found = 1; | ||
413 | break; | 590 | break; |
591 | } | ||
414 | } | 592 | } |
415 | if (!p) | 593 | if (!found) |
416 | return idx; | 594 | return idx; |
417 | } | 595 | } |
418 | } | 596 | } |
419 | 597 | ||
598 | static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2) | ||
599 | { | ||
600 | u32 *p1 = (u32 *) s1; | ||
601 | u32 *p2 = (u32 *) s2; | ||
602 | int len = sizeof(struct xfrm_selector) / sizeof(u32); | ||
603 | int i; | ||
604 | |||
605 | for (i = 0; i < len; i++) { | ||
606 | if (p1[i] != p2[i]) | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
420 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | 613 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) |
421 | { | 614 | { |
422 | struct xfrm_policy *pol, **p; | 615 | struct xfrm_policy *pol; |
423 | struct xfrm_policy *delpol = NULL; | 616 | struct xfrm_policy *delpol; |
424 | struct xfrm_policy **newpos = NULL; | 617 | struct hlist_head *chain; |
618 | struct hlist_node *entry, *newpos, *last; | ||
425 | struct dst_entry *gc_list; | 619 | struct dst_entry *gc_list; |
426 | 620 | ||
427 | write_lock_bh(&xfrm_policy_lock); | 621 | write_lock_bh(&xfrm_policy_lock); |
428 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 622 | chain = policy_hash_bysel(&policy->selector, policy->family, dir); |
429 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && | 623 | delpol = NULL; |
624 | newpos = NULL; | ||
625 | last = NULL; | ||
626 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
627 | if (!delpol && | ||
628 | pol->type == policy->type && | ||
629 | !selector_cmp(&pol->selector, &policy->selector) && | ||
430 | xfrm_sec_ctx_match(pol->security, policy->security)) { | 630 | xfrm_sec_ctx_match(pol->security, policy->security)) { |
431 | if (excl) { | 631 | if (excl) { |
432 | write_unlock_bh(&xfrm_policy_lock); | 632 | write_unlock_bh(&xfrm_policy_lock); |
433 | return -EEXIST; | 633 | return -EEXIST; |
434 | } | 634 | } |
435 | *p = pol->next; | ||
436 | delpol = pol; | 635 | delpol = pol; |
437 | if (policy->priority > pol->priority) | 636 | if (policy->priority > pol->priority) |
438 | continue; | 637 | continue; |
439 | } else if (policy->priority >= pol->priority) { | 638 | } else if (policy->priority >= pol->priority) { |
440 | p = &pol->next; | 639 | last = &pol->bydst; |
441 | continue; | 640 | continue; |
442 | } | 641 | } |
443 | if (!newpos) | 642 | if (!newpos) |
444 | newpos = p; | 643 | newpos = &pol->bydst; |
445 | if (delpol) | 644 | if (delpol) |
446 | break; | 645 | break; |
447 | p = &pol->next; | 646 | last = &pol->bydst; |
448 | } | 647 | } |
648 | if (!newpos) | ||
649 | newpos = last; | ||
449 | if (newpos) | 650 | if (newpos) |
450 | p = newpos; | 651 | hlist_add_after(newpos, &policy->bydst); |
652 | else | ||
653 | hlist_add_head(&policy->bydst, chain); | ||
451 | xfrm_pol_hold(policy); | 654 | xfrm_pol_hold(policy); |
452 | policy->next = *p; | 655 | xfrm_policy_count[dir]++; |
453 | *p = policy; | ||
454 | atomic_inc(&flow_cache_genid); | 656 | atomic_inc(&flow_cache_genid); |
455 | policy->index = delpol ? delpol->index : xfrm_gen_index(dir); | 657 | if (delpol) { |
658 | hlist_del(&delpol->bydst); | ||
659 | hlist_del(&delpol->byidx); | ||
660 | xfrm_policy_count[dir]--; | ||
661 | } | ||
662 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); | ||
663 | hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index)); | ||
456 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; | 664 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; |
457 | policy->curlft.use_time = 0; | 665 | policy->curlft.use_time = 0; |
458 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 666 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
@@ -461,10 +669,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
461 | 669 | ||
462 | if (delpol) | 670 | if (delpol) |
463 | xfrm_policy_kill(delpol); | 671 | xfrm_policy_kill(delpol); |
672 | else if (xfrm_bydst_should_resize(dir, NULL)) | ||
673 | schedule_work(&xfrm_hash_work); | ||
464 | 674 | ||
465 | read_lock_bh(&xfrm_policy_lock); | 675 | read_lock_bh(&xfrm_policy_lock); |
466 | gc_list = NULL; | 676 | gc_list = NULL; |
467 | for (policy = policy->next; policy; policy = policy->next) { | 677 | entry = &policy->bydst; |
678 | hlist_for_each_entry_continue(policy, entry, bydst) { | ||
468 | struct dst_entry *dst; | 679 | struct dst_entry *dst; |
469 | 680 | ||
470 | write_lock(&policy->lock); | 681 | write_lock(&policy->lock); |
@@ -493,87 +704,146 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
493 | } | 704 | } |
494 | EXPORT_SYMBOL(xfrm_policy_insert); | 705 | EXPORT_SYMBOL(xfrm_policy_insert); |
495 | 706 | ||
496 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 707 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
708 | struct xfrm_selector *sel, | ||
497 | struct xfrm_sec_ctx *ctx, int delete) | 709 | struct xfrm_sec_ctx *ctx, int delete) |
498 | { | 710 | { |
499 | struct xfrm_policy *pol, **p; | 711 | struct xfrm_policy *pol, *ret; |
712 | struct hlist_head *chain; | ||
713 | struct hlist_node *entry; | ||
500 | 714 | ||
501 | write_lock_bh(&xfrm_policy_lock); | 715 | write_lock_bh(&xfrm_policy_lock); |
502 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 716 | chain = policy_hash_bysel(sel, sel->family, dir); |
503 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && | 717 | ret = NULL; |
504 | (xfrm_sec_ctx_match(ctx, pol->security))) { | 718 | hlist_for_each_entry(pol, entry, chain, bydst) { |
719 | if (pol->type == type && | ||
720 | !selector_cmp(sel, &pol->selector) && | ||
721 | xfrm_sec_ctx_match(ctx, pol->security)) { | ||
505 | xfrm_pol_hold(pol); | 722 | xfrm_pol_hold(pol); |
506 | if (delete) | 723 | if (delete) { |
507 | *p = pol->next; | 724 | hlist_del(&pol->bydst); |
725 | hlist_del(&pol->byidx); | ||
726 | xfrm_policy_count[dir]--; | ||
727 | } | ||
728 | ret = pol; | ||
508 | break; | 729 | break; |
509 | } | 730 | } |
510 | } | 731 | } |
511 | write_unlock_bh(&xfrm_policy_lock); | 732 | write_unlock_bh(&xfrm_policy_lock); |
512 | 733 | ||
513 | if (pol && delete) { | 734 | if (ret && delete) { |
514 | atomic_inc(&flow_cache_genid); | 735 | atomic_inc(&flow_cache_genid); |
515 | xfrm_policy_kill(pol); | 736 | xfrm_policy_kill(ret); |
516 | } | 737 | } |
517 | return pol; | 738 | return ret; |
518 | } | 739 | } |
519 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 740 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
520 | 741 | ||
521 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 742 | struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete) |
522 | { | 743 | { |
523 | struct xfrm_policy *pol, **p; | 744 | struct xfrm_policy *pol, *ret; |
745 | struct hlist_head *chain; | ||
746 | struct hlist_node *entry; | ||
524 | 747 | ||
525 | write_lock_bh(&xfrm_policy_lock); | 748 | write_lock_bh(&xfrm_policy_lock); |
526 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 749 | chain = xfrm_policy_byidx + idx_hash(id); |
527 | if (pol->index == id) { | 750 | ret = NULL; |
751 | hlist_for_each_entry(pol, entry, chain, byidx) { | ||
752 | if (pol->type == type && pol->index == id) { | ||
528 | xfrm_pol_hold(pol); | 753 | xfrm_pol_hold(pol); |
529 | if (delete) | 754 | if (delete) { |
530 | *p = pol->next; | 755 | hlist_del(&pol->bydst); |
756 | hlist_del(&pol->byidx); | ||
757 | xfrm_policy_count[dir]--; | ||
758 | } | ||
759 | ret = pol; | ||
531 | break; | 760 | break; |
532 | } | 761 | } |
533 | } | 762 | } |
534 | write_unlock_bh(&xfrm_policy_lock); | 763 | write_unlock_bh(&xfrm_policy_lock); |
535 | 764 | ||
536 | if (pol && delete) { | 765 | if (ret && delete) { |
537 | atomic_inc(&flow_cache_genid); | 766 | atomic_inc(&flow_cache_genid); |
538 | xfrm_policy_kill(pol); | 767 | xfrm_policy_kill(ret); |
539 | } | 768 | } |
540 | return pol; | 769 | return ret; |
541 | } | 770 | } |
542 | EXPORT_SYMBOL(xfrm_policy_byid); | 771 | EXPORT_SYMBOL(xfrm_policy_byid); |
543 | 772 | ||
544 | void xfrm_policy_flush(void) | 773 | void xfrm_policy_flush(u8 type) |
545 | { | 774 | { |
546 | struct xfrm_policy *xp; | ||
547 | int dir; | 775 | int dir; |
548 | 776 | ||
549 | write_lock_bh(&xfrm_policy_lock); | 777 | write_lock_bh(&xfrm_policy_lock); |
550 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 778 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
551 | while ((xp = xfrm_policy_list[dir]) != NULL) { | 779 | struct xfrm_policy *pol; |
552 | xfrm_policy_list[dir] = xp->next; | 780 | struct hlist_node *entry; |
781 | int i; | ||
782 | |||
783 | again1: | ||
784 | hlist_for_each_entry(pol, entry, | ||
785 | &xfrm_policy_inexact[dir], bydst) { | ||
786 | if (pol->type != type) | ||
787 | continue; | ||
788 | hlist_del(&pol->bydst); | ||
789 | hlist_del(&pol->byidx); | ||
553 | write_unlock_bh(&xfrm_policy_lock); | 790 | write_unlock_bh(&xfrm_policy_lock); |
554 | 791 | ||
555 | xfrm_policy_kill(xp); | 792 | xfrm_policy_kill(pol); |
556 | 793 | ||
557 | write_lock_bh(&xfrm_policy_lock); | 794 | write_lock_bh(&xfrm_policy_lock); |
795 | goto again1; | ||
558 | } | 796 | } |
797 | |||
798 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
799 | again2: | ||
800 | hlist_for_each_entry(pol, entry, | ||
801 | xfrm_policy_bydst[dir].table + i, | ||
802 | bydst) { | ||
803 | if (pol->type != type) | ||
804 | continue; | ||
805 | hlist_del(&pol->bydst); | ||
806 | hlist_del(&pol->byidx); | ||
807 | write_unlock_bh(&xfrm_policy_lock); | ||
808 | |||
809 | xfrm_policy_kill(pol); | ||
810 | |||
811 | write_lock_bh(&xfrm_policy_lock); | ||
812 | goto again2; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | xfrm_policy_count[dir] = 0; | ||
559 | } | 817 | } |
560 | atomic_inc(&flow_cache_genid); | 818 | atomic_inc(&flow_cache_genid); |
561 | write_unlock_bh(&xfrm_policy_lock); | 819 | write_unlock_bh(&xfrm_policy_lock); |
562 | } | 820 | } |
563 | EXPORT_SYMBOL(xfrm_policy_flush); | 821 | EXPORT_SYMBOL(xfrm_policy_flush); |
564 | 822 | ||
565 | int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | 823 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), |
566 | void *data) | 824 | void *data) |
567 | { | 825 | { |
568 | struct xfrm_policy *xp; | 826 | struct xfrm_policy *pol; |
569 | int dir; | 827 | struct hlist_node *entry; |
570 | int count = 0; | 828 | int dir, count, error; |
571 | int error = 0; | ||
572 | 829 | ||
573 | read_lock_bh(&xfrm_policy_lock); | 830 | read_lock_bh(&xfrm_policy_lock); |
831 | count = 0; | ||
574 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 832 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
575 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) | 833 | struct hlist_head *table = xfrm_policy_bydst[dir].table; |
576 | count++; | 834 | int i; |
835 | |||
836 | hlist_for_each_entry(pol, entry, | ||
837 | &xfrm_policy_inexact[dir], bydst) { | ||
838 | if (pol->type == type) | ||
839 | count++; | ||
840 | } | ||
841 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
842 | hlist_for_each_entry(pol, entry, table + i, bydst) { | ||
843 | if (pol->type == type) | ||
844 | count++; | ||
845 | } | ||
846 | } | ||
577 | } | 847 | } |
578 | 848 | ||
579 | if (count == 0) { | 849 | if (count == 0) { |
@@ -582,13 +852,28 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
582 | } | 852 | } |
583 | 853 | ||
584 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 854 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
585 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) { | 855 | struct hlist_head *table = xfrm_policy_bydst[dir].table; |
586 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); | 856 | int i; |
857 | |||
858 | hlist_for_each_entry(pol, entry, | ||
859 | &xfrm_policy_inexact[dir], bydst) { | ||
860 | if (pol->type != type) | ||
861 | continue; | ||
862 | error = func(pol, dir % XFRM_POLICY_MAX, --count, data); | ||
587 | if (error) | 863 | if (error) |
588 | goto out; | 864 | goto out; |
589 | } | 865 | } |
866 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
867 | hlist_for_each_entry(pol, entry, table + i, bydst) { | ||
868 | if (pol->type != type) | ||
869 | continue; | ||
870 | error = func(pol, dir % XFRM_POLICY_MAX, --count, data); | ||
871 | if (error) | ||
872 | goto out; | ||
873 | } | ||
874 | } | ||
590 | } | 875 | } |
591 | 876 | error = 0; | |
592 | out: | 877 | out: |
593 | read_unlock_bh(&xfrm_policy_lock); | 878 | read_unlock_bh(&xfrm_policy_lock); |
594 | return error; | 879 | return error; |
@@ -597,29 +882,79 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
597 | 882 | ||
598 | /* Find policy to apply to this flow. */ | 883 | /* Find policy to apply to this flow. */ |
599 | 884 | ||
600 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, | 885 | static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, |
601 | void **objp, atomic_t **obj_refp) | 886 | u8 type, u16 family, int dir) |
602 | { | 887 | { |
603 | struct xfrm_policy *pol; | 888 | struct xfrm_selector *sel = &pol->selector; |
889 | int match; | ||
604 | 890 | ||
605 | read_lock_bh(&xfrm_policy_lock); | 891 | if (pol->family != family || |
606 | for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) { | 892 | pol->type != type) |
607 | struct xfrm_selector *sel = &pol->selector; | 893 | return 0; |
608 | int match; | ||
609 | 894 | ||
610 | if (pol->family != family) | 895 | match = xfrm_selector_match(sel, fl, family); |
611 | continue; | 896 | if (match) { |
897 | if (!security_xfrm_policy_lookup(pol, fl->secid, dir)) | ||
898 | return 1; | ||
899 | } | ||
612 | 900 | ||
613 | match = xfrm_selector_match(sel, fl, family); | 901 | return 0; |
902 | } | ||
614 | 903 | ||
615 | if (match) { | 904 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, |
616 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { | 905 | u16 family, u8 dir) |
617 | xfrm_pol_hold(pol); | 906 | { |
618 | break; | 907 | struct xfrm_policy *pol, *ret; |
619 | } | 908 | xfrm_address_t *daddr, *saddr; |
909 | struct hlist_node *entry; | ||
910 | struct hlist_head *chain; | ||
911 | u32 priority = ~0U; | ||
912 | |||
913 | daddr = xfrm_flowi_daddr(fl, family); | ||
914 | saddr = xfrm_flowi_saddr(fl, family); | ||
915 | if (unlikely(!daddr || !saddr)) | ||
916 | return NULL; | ||
917 | |||
918 | read_lock_bh(&xfrm_policy_lock); | ||
919 | chain = policy_hash_direct(daddr, saddr, family, dir); | ||
920 | ret = NULL; | ||
921 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
922 | if (xfrm_policy_match(pol, fl, type, family, dir)) { | ||
923 | ret = pol; | ||
924 | priority = ret->priority; | ||
925 | break; | ||
926 | } | ||
927 | } | ||
928 | chain = &xfrm_policy_inexact[dir]; | ||
929 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
930 | if (xfrm_policy_match(pol, fl, type, family, dir) && | ||
931 | pol->priority < priority) { | ||
932 | ret = pol; | ||
933 | break; | ||
620 | } | 934 | } |
621 | } | 935 | } |
936 | if (ret) | ||
937 | xfrm_pol_hold(ret); | ||
622 | read_unlock_bh(&xfrm_policy_lock); | 938 | read_unlock_bh(&xfrm_policy_lock); |
939 | |||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | ||
944 | void **objp, atomic_t **obj_refp) | ||
945 | { | ||
946 | struct xfrm_policy *pol; | ||
947 | |||
948 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
949 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
950 | if (pol) | ||
951 | goto end; | ||
952 | #endif | ||
953 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
954 | |||
955 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
956 | end: | ||
957 | #endif | ||
623 | if ((*objp = (void *) pol) != NULL) | 958 | if ((*objp = (void *) pol) != NULL) |
624 | *obj_refp = &pol->refcnt; | 959 | *obj_refp = &pol->refcnt; |
625 | } | 960 | } |
@@ -641,7 +976,7 @@ static inline int policy_to_flow_dir(int dir) | |||
641 | }; | 976 | }; |
642 | } | 977 | } |
643 | 978 | ||
644 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | 979 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) |
645 | { | 980 | { |
646 | struct xfrm_policy *pol; | 981 | struct xfrm_policy *pol; |
647 | 982 | ||
@@ -652,7 +987,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
652 | int err = 0; | 987 | int err = 0; |
653 | 988 | ||
654 | if (match) | 989 | if (match) |
655 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | 990 | err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir)); |
656 | 991 | ||
657 | if (match && !err) | 992 | if (match && !err) |
658 | xfrm_pol_hold(pol); | 993 | xfrm_pol_hold(pol); |
@@ -665,24 +1000,29 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
665 | 1000 | ||
666 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | 1001 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) |
667 | { | 1002 | { |
668 | pol->next = xfrm_policy_list[dir]; | 1003 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, |
669 | xfrm_policy_list[dir] = pol; | 1004 | pol->family, dir); |
1005 | |||
1006 | hlist_add_head(&pol->bydst, chain); | ||
1007 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); | ||
1008 | xfrm_policy_count[dir]++; | ||
670 | xfrm_pol_hold(pol); | 1009 | xfrm_pol_hold(pol); |
1010 | |||
1011 | if (xfrm_bydst_should_resize(dir, NULL)) | ||
1012 | schedule_work(&xfrm_hash_work); | ||
671 | } | 1013 | } |
672 | 1014 | ||
673 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 1015 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
674 | int dir) | 1016 | int dir) |
675 | { | 1017 | { |
676 | struct xfrm_policy **polp; | 1018 | if (hlist_unhashed(&pol->bydst)) |
1019 | return NULL; | ||
677 | 1020 | ||
678 | for (polp = &xfrm_policy_list[dir]; | 1021 | hlist_del(&pol->bydst); |
679 | *polp != NULL; polp = &(*polp)->next) { | 1022 | hlist_del(&pol->byidx); |
680 | if (*polp == pol) { | 1023 | xfrm_policy_count[dir]--; |
681 | *polp = pol->next; | 1024 | |
682 | return pol; | 1025 | return pol; |
683 | } | ||
684 | } | ||
685 | return NULL; | ||
686 | } | 1026 | } |
687 | 1027 | ||
688 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | 1028 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) |
@@ -704,12 +1044,17 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
704 | { | 1044 | { |
705 | struct xfrm_policy *old_pol; | 1045 | struct xfrm_policy *old_pol; |
706 | 1046 | ||
1047 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1048 | if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) | ||
1049 | return -EINVAL; | ||
1050 | #endif | ||
1051 | |||
707 | write_lock_bh(&xfrm_policy_lock); | 1052 | write_lock_bh(&xfrm_policy_lock); |
708 | old_pol = sk->sk_policy[dir]; | 1053 | old_pol = sk->sk_policy[dir]; |
709 | sk->sk_policy[dir] = pol; | 1054 | sk->sk_policy[dir] = pol; |
710 | if (pol) { | 1055 | if (pol) { |
711 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; | 1056 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; |
712 | pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); | 1057 | pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir); |
713 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 1058 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
714 | } | 1059 | } |
715 | if (old_pol) | 1060 | if (old_pol) |
@@ -738,6 +1083,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
738 | newp->flags = old->flags; | 1083 | newp->flags = old->flags; |
739 | newp->xfrm_nr = old->xfrm_nr; | 1084 | newp->xfrm_nr = old->xfrm_nr; |
740 | newp->index = old->index; | 1085 | newp->index = old->index; |
1086 | newp->type = old->type; | ||
741 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 1087 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
742 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 1088 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
743 | write_lock_bh(&xfrm_policy_lock); | 1089 | write_lock_bh(&xfrm_policy_lock); |
@@ -761,17 +1107,32 @@ int __xfrm_sk_clone_policy(struct sock *sk) | |||
761 | return 0; | 1107 | return 0; |
762 | } | 1108 | } |
763 | 1109 | ||
1110 | static int | ||
1111 | xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote, | ||
1112 | unsigned short family) | ||
1113 | { | ||
1114 | int err; | ||
1115 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
1116 | |||
1117 | if (unlikely(afinfo == NULL)) | ||
1118 | return -EINVAL; | ||
1119 | err = afinfo->get_saddr(local, remote); | ||
1120 | xfrm_policy_put_afinfo(afinfo); | ||
1121 | return err; | ||
1122 | } | ||
1123 | |||
764 | /* Resolve list of templates for the flow, given policy. */ | 1124 | /* Resolve list of templates for the flow, given policy. */ |
765 | 1125 | ||
766 | static int | 1126 | static int |
767 | xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | 1127 | xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, |
768 | struct xfrm_state **xfrm, | 1128 | struct xfrm_state **xfrm, |
769 | unsigned short family) | 1129 | unsigned short family) |
770 | { | 1130 | { |
771 | int nx; | 1131 | int nx; |
772 | int i, error; | 1132 | int i, error; |
773 | xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); | 1133 | xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); |
774 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); | 1134 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); |
1135 | xfrm_address_t tmp; | ||
775 | 1136 | ||
776 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { | 1137 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { |
777 | struct xfrm_state *x; | 1138 | struct xfrm_state *x; |
@@ -779,9 +1140,15 @@ xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | |||
779 | xfrm_address_t *local = saddr; | 1140 | xfrm_address_t *local = saddr; |
780 | struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; | 1141 | struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; |
781 | 1142 | ||
782 | if (tmpl->mode) { | 1143 | if (tmpl->mode == XFRM_MODE_TUNNEL) { |
783 | remote = &tmpl->id.daddr; | 1144 | remote = &tmpl->id.daddr; |
784 | local = &tmpl->saddr; | 1145 | local = &tmpl->saddr; |
1146 | if (xfrm_addr_any(local, family)) { | ||
1147 | error = xfrm_get_saddr(&tmp, remote, family); | ||
1148 | if (error) | ||
1149 | goto fail; | ||
1150 | local = &tmp; | ||
1151 | } | ||
785 | } | 1152 | } |
786 | 1153 | ||
787 | x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); | 1154 | x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); |
@@ -809,6 +1176,45 @@ fail: | |||
809 | return error; | 1176 | return error; |
810 | } | 1177 | } |
811 | 1178 | ||
1179 | static int | ||
1180 | xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | ||
1181 | struct xfrm_state **xfrm, | ||
1182 | unsigned short family) | ||
1183 | { | ||
1184 | struct xfrm_state *tp[XFRM_MAX_DEPTH]; | ||
1185 | struct xfrm_state **tpp = (npols > 1) ? tp : xfrm; | ||
1186 | int cnx = 0; | ||
1187 | int error; | ||
1188 | int ret; | ||
1189 | int i; | ||
1190 | |||
1191 | for (i = 0; i < npols; i++) { | ||
1192 | if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { | ||
1193 | error = -ENOBUFS; | ||
1194 | goto fail; | ||
1195 | } | ||
1196 | |||
1197 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family); | ||
1198 | if (ret < 0) { | ||
1199 | error = ret; | ||
1200 | goto fail; | ||
1201 | } else | ||
1202 | cnx += ret; | ||
1203 | } | ||
1204 | |||
1205 | /* found states are sorted for outbound processing */ | ||
1206 | if (npols > 1) | ||
1207 | xfrm_state_sort(xfrm, tpp, cnx, family); | ||
1208 | |||
1209 | return cnx; | ||
1210 | |||
1211 | fail: | ||
1212 | for (cnx--; cnx>=0; cnx--) | ||
1213 | xfrm_state_put(tpp[cnx]); | ||
1214 | return error; | ||
1215 | |||
1216 | } | ||
1217 | |||
812 | /* Check that the bundle accepts the flow and its components are | 1218 | /* Check that the bundle accepts the flow and its components are |
813 | * still valid. | 1219 | * still valid. |
814 | */ | 1220 | */ |
@@ -855,6 +1261,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
855 | struct sock *sk, int flags) | 1261 | struct sock *sk, int flags) |
856 | { | 1262 | { |
857 | struct xfrm_policy *policy; | 1263 | struct xfrm_policy *policy; |
1264 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1265 | int npols; | ||
1266 | int pol_dead; | ||
1267 | int xfrm_nr; | ||
1268 | int pi; | ||
858 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | 1269 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
859 | struct dst_entry *dst, *dst_orig = *dst_p; | 1270 | struct dst_entry *dst, *dst_orig = *dst_p; |
860 | int nx = 0; | 1271 | int nx = 0; |
@@ -862,19 +1273,26 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
862 | u32 genid; | 1273 | u32 genid; |
863 | u16 family; | 1274 | u16 family; |
864 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | 1275 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); |
865 | u32 sk_sid = security_sk_sid(sk, fl, dir); | 1276 | |
866 | restart: | 1277 | restart: |
867 | genid = atomic_read(&flow_cache_genid); | 1278 | genid = atomic_read(&flow_cache_genid); |
868 | policy = NULL; | 1279 | policy = NULL; |
1280 | for (pi = 0; pi < ARRAY_SIZE(pols); pi++) | ||
1281 | pols[pi] = NULL; | ||
1282 | npols = 0; | ||
1283 | pol_dead = 0; | ||
1284 | xfrm_nr = 0; | ||
1285 | |||
869 | if (sk && sk->sk_policy[1]) | 1286 | if (sk && sk->sk_policy[1]) |
870 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); | 1287 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
871 | 1288 | ||
872 | if (!policy) { | 1289 | if (!policy) { |
873 | /* To accelerate a bit... */ | 1290 | /* To accelerate a bit... */ |
874 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 1291 | if ((dst_orig->flags & DST_NOXFRM) || |
1292 | !xfrm_policy_count[XFRM_POLICY_OUT]) | ||
875 | return 0; | 1293 | return 0; |
876 | 1294 | ||
877 | policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family, | 1295 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
878 | dir, xfrm_policy_lookup); | 1296 | dir, xfrm_policy_lookup); |
879 | } | 1297 | } |
880 | 1298 | ||
@@ -883,6 +1301,9 @@ restart: | |||
883 | 1301 | ||
884 | family = dst_orig->ops->family; | 1302 | family = dst_orig->ops->family; |
885 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; | 1303 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; |
1304 | pols[0] = policy; | ||
1305 | npols ++; | ||
1306 | xfrm_nr += pols[0]->xfrm_nr; | ||
886 | 1307 | ||
887 | switch (policy->action) { | 1308 | switch (policy->action) { |
888 | case XFRM_POLICY_BLOCK: | 1309 | case XFRM_POLICY_BLOCK: |
@@ -891,11 +1312,13 @@ restart: | |||
891 | goto error; | 1312 | goto error; |
892 | 1313 | ||
893 | case XFRM_POLICY_ALLOW: | 1314 | case XFRM_POLICY_ALLOW: |
1315 | #ifndef CONFIG_XFRM_SUB_POLICY | ||
894 | if (policy->xfrm_nr == 0) { | 1316 | if (policy->xfrm_nr == 0) { |
895 | /* Flow passes not transformed. */ | 1317 | /* Flow passes not transformed. */ |
896 | xfrm_pol_put(policy); | 1318 | xfrm_pol_put(policy); |
897 | return 0; | 1319 | return 0; |
898 | } | 1320 | } |
1321 | #endif | ||
899 | 1322 | ||
900 | /* Try to find matching bundle. | 1323 | /* Try to find matching bundle. |
901 | * | 1324 | * |
@@ -911,7 +1334,36 @@ restart: | |||
911 | if (dst) | 1334 | if (dst) |
912 | break; | 1335 | break; |
913 | 1336 | ||
914 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1337 | #ifdef CONFIG_XFRM_SUB_POLICY |
1338 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1339 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1340 | fl, family, | ||
1341 | XFRM_POLICY_OUT); | ||
1342 | if (pols[1]) { | ||
1343 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | ||
1344 | err = -EPERM; | ||
1345 | goto error; | ||
1346 | } | ||
1347 | npols ++; | ||
1348 | xfrm_nr += pols[1]->xfrm_nr; | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | /* | ||
1353 | * Because neither flowi nor bundle information knows about | ||
1354 | * transformation template size. On more than one policy usage | ||
1355 | * we can realize whether all of them is bypass or not after | ||
1356 | * they are searched. See above not-transformed bypass | ||
1357 | * is surrounded by non-sub policy configuration, too. | ||
1358 | */ | ||
1359 | if (xfrm_nr == 0) { | ||
1360 | /* Flow passes not transformed. */ | ||
1361 | xfrm_pols_put(pols, npols); | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | #endif | ||
1366 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
915 | 1367 | ||
916 | if (unlikely(nx<0)) { | 1368 | if (unlikely(nx<0)) { |
917 | err = nx; | 1369 | err = nx; |
@@ -924,7 +1376,7 @@ restart: | |||
924 | set_current_state(TASK_RUNNING); | 1376 | set_current_state(TASK_RUNNING); |
925 | remove_wait_queue(&km_waitq, &wait); | 1377 | remove_wait_queue(&km_waitq, &wait); |
926 | 1378 | ||
927 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1379 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); |
928 | 1380 | ||
929 | if (nx == -EAGAIN && signal_pending(current)) { | 1381 | if (nx == -EAGAIN && signal_pending(current)) { |
930 | err = -ERESTART; | 1382 | err = -ERESTART; |
@@ -932,7 +1384,7 @@ restart: | |||
932 | } | 1384 | } |
933 | if (nx == -EAGAIN || | 1385 | if (nx == -EAGAIN || |
934 | genid != atomic_read(&flow_cache_genid)) { | 1386 | genid != atomic_read(&flow_cache_genid)) { |
935 | xfrm_pol_put(policy); | 1387 | xfrm_pols_put(pols, npols); |
936 | goto restart; | 1388 | goto restart; |
937 | } | 1389 | } |
938 | err = nx; | 1390 | err = nx; |
@@ -942,7 +1394,7 @@ restart: | |||
942 | } | 1394 | } |
943 | if (nx == 0) { | 1395 | if (nx == 0) { |
944 | /* Flow passes not transformed. */ | 1396 | /* Flow passes not transformed. */ |
945 | xfrm_pol_put(policy); | 1397 | xfrm_pols_put(pols, npols); |
946 | return 0; | 1398 | return 0; |
947 | } | 1399 | } |
948 | 1400 | ||
@@ -956,8 +1408,14 @@ restart: | |||
956 | goto error; | 1408 | goto error; |
957 | } | 1409 | } |
958 | 1410 | ||
1411 | for (pi = 0; pi < npols; pi++) { | ||
1412 | read_lock_bh(&pols[pi]->lock); | ||
1413 | pol_dead |= pols[pi]->dead; | ||
1414 | read_unlock_bh(&pols[pi]->lock); | ||
1415 | } | ||
1416 | |||
959 | write_lock_bh(&policy->lock); | 1417 | write_lock_bh(&policy->lock); |
960 | if (unlikely(policy->dead || stale_bundle(dst))) { | 1418 | if (unlikely(pol_dead || stale_bundle(dst))) { |
961 | /* Wow! While we worked on resolving, this | 1419 | /* Wow! While we worked on resolving, this |
962 | * policy has gone. Retry. It is not paranoia, | 1420 | * policy has gone. Retry. It is not paranoia, |
963 | * we just cannot enlist new bundle to dead object. | 1421 | * we just cannot enlist new bundle to dead object. |
@@ -977,17 +1435,34 @@ restart: | |||
977 | } | 1435 | } |
978 | *dst_p = dst; | 1436 | *dst_p = dst; |
979 | dst_release(dst_orig); | 1437 | dst_release(dst_orig); |
980 | xfrm_pol_put(policy); | 1438 | xfrm_pols_put(pols, npols); |
981 | return 0; | 1439 | return 0; |
982 | 1440 | ||
983 | error: | 1441 | error: |
984 | dst_release(dst_orig); | 1442 | dst_release(dst_orig); |
985 | xfrm_pol_put(policy); | 1443 | xfrm_pols_put(pols, npols); |
986 | *dst_p = NULL; | 1444 | *dst_p = NULL; |
987 | return err; | 1445 | return err; |
988 | } | 1446 | } |
989 | EXPORT_SYMBOL(xfrm_lookup); | 1447 | EXPORT_SYMBOL(xfrm_lookup); |
990 | 1448 | ||
1449 | static inline int | ||
1450 | xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl) | ||
1451 | { | ||
1452 | struct xfrm_state *x; | ||
1453 | int err; | ||
1454 | |||
1455 | if (!skb->sp || idx < 0 || idx >= skb->sp->len) | ||
1456 | return 0; | ||
1457 | x = skb->sp->xvec[idx]; | ||
1458 | if (!x->type->reject) | ||
1459 | return 0; | ||
1460 | xfrm_state_hold(x); | ||
1461 | err = x->type->reject(x, skb, fl); | ||
1462 | xfrm_state_put(x); | ||
1463 | return err; | ||
1464 | } | ||
1465 | |||
991 | /* When skb is transformed back to its "native" form, we have to | 1466 | /* When skb is transformed back to its "native" form, we have to |
992 | * check policy restrictions. At the moment we make this in maximally | 1467 | * check policy restrictions. At the moment we make this in maximally |
993 | * stupid way. Shame on me. :-) Of course, connected sockets must | 1468 | * stupid way. Shame on me. :-) Of course, connected sockets must |
@@ -1004,10 +1479,19 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, | |||
1004 | (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && | 1479 | (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && |
1005 | (x->props.reqid == tmpl->reqid || !tmpl->reqid) && | 1480 | (x->props.reqid == tmpl->reqid || !tmpl->reqid) && |
1006 | x->props.mode == tmpl->mode && | 1481 | x->props.mode == tmpl->mode && |
1007 | (tmpl->aalgos & (1<<x->props.aalgo)) && | 1482 | ((tmpl->aalgos & (1<<x->props.aalgo)) || |
1008 | !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family)); | 1483 | !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) && |
1484 | !(x->props.mode != XFRM_MODE_TRANSPORT && | ||
1485 | xfrm_state_addr_cmp(tmpl, x, family)); | ||
1009 | } | 1486 | } |
1010 | 1487 | ||
1488 | /* | ||
1489 | * 0 or more than 0 is returned when validation is succeeded (either bypass | ||
1490 | * because of optional transport mode, or next index of the mathced secpath | ||
1491 | * state with the template. | ||
1492 | * -1 is returned when no matching template is found. | ||
1493 | * Otherwise "-2 - errored_index" is returned. | ||
1494 | */ | ||
1011 | static inline int | 1495 | static inline int |
1012 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | 1496 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, |
1013 | unsigned short family) | 1497 | unsigned short family) |
@@ -1015,15 +1499,18 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | |||
1015 | int idx = start; | 1499 | int idx = start; |
1016 | 1500 | ||
1017 | if (tmpl->optional) { | 1501 | if (tmpl->optional) { |
1018 | if (!tmpl->mode) | 1502 | if (tmpl->mode == XFRM_MODE_TRANSPORT) |
1019 | return start; | 1503 | return start; |
1020 | } else | 1504 | } else |
1021 | start = -1; | 1505 | start = -1; |
1022 | for (; idx < sp->len; idx++) { | 1506 | for (; idx < sp->len; idx++) { |
1023 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) | 1507 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) |
1024 | return ++idx; | 1508 | return ++idx; |
1025 | if (sp->xvec[idx]->props.mode) | 1509 | if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { |
1510 | if (start == -1) | ||
1511 | start = -2-idx; | ||
1026 | break; | 1512 | break; |
1513 | } | ||
1027 | } | 1514 | } |
1028 | return start; | 1515 | return start; |
1029 | } | 1516 | } |
@@ -1032,21 +1519,25 @@ int | |||
1032 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) | 1519 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) |
1033 | { | 1520 | { |
1034 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1521 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
1522 | int err; | ||
1035 | 1523 | ||
1036 | if (unlikely(afinfo == NULL)) | 1524 | if (unlikely(afinfo == NULL)) |
1037 | return -EAFNOSUPPORT; | 1525 | return -EAFNOSUPPORT; |
1038 | 1526 | ||
1039 | afinfo->decode_session(skb, fl); | 1527 | afinfo->decode_session(skb, fl); |
1528 | err = security_xfrm_decode_session(skb, &fl->secid); | ||
1040 | xfrm_policy_put_afinfo(afinfo); | 1529 | xfrm_policy_put_afinfo(afinfo); |
1041 | return 0; | 1530 | return err; |
1042 | } | 1531 | } |
1043 | EXPORT_SYMBOL(xfrm_decode_session); | 1532 | EXPORT_SYMBOL(xfrm_decode_session); |
1044 | 1533 | ||
1045 | static inline int secpath_has_tunnel(struct sec_path *sp, int k) | 1534 | static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp) |
1046 | { | 1535 | { |
1047 | for (; k < sp->len; k++) { | 1536 | for (; k < sp->len; k++) { |
1048 | if (sp->xvec[k]->props.mode) | 1537 | if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) { |
1538 | *idxp = k; | ||
1049 | return 1; | 1539 | return 1; |
1540 | } | ||
1050 | } | 1541 | } |
1051 | 1542 | ||
1052 | return 0; | 1543 | return 0; |
@@ -1056,16 +1547,18 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1056 | unsigned short family) | 1547 | unsigned short family) |
1057 | { | 1548 | { |
1058 | struct xfrm_policy *pol; | 1549 | struct xfrm_policy *pol; |
1550 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1551 | int npols = 0; | ||
1552 | int xfrm_nr; | ||
1553 | int pi; | ||
1059 | struct flowi fl; | 1554 | struct flowi fl; |
1060 | u8 fl_dir = policy_to_flow_dir(dir); | 1555 | u8 fl_dir = policy_to_flow_dir(dir); |
1061 | u32 sk_sid; | 1556 | int xerr_idx = -1; |
1062 | 1557 | ||
1063 | if (xfrm_decode_session(skb, &fl, family) < 0) | 1558 | if (xfrm_decode_session(skb, &fl, family) < 0) |
1064 | return 0; | 1559 | return 0; |
1065 | nf_nat_decode_session(skb, &fl, family); | 1560 | nf_nat_decode_session(skb, &fl, family); |
1066 | 1561 | ||
1067 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
1068 | |||
1069 | /* First, check used SA against their selectors. */ | 1562 | /* First, check used SA against their selectors. */ |
1070 | if (skb->sp) { | 1563 | if (skb->sp) { |
1071 | int i; | 1564 | int i; |
@@ -1079,46 +1572,90 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1079 | 1572 | ||
1080 | pol = NULL; | 1573 | pol = NULL; |
1081 | if (sk && sk->sk_policy[dir]) | 1574 | if (sk && sk->sk_policy[dir]) |
1082 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); | 1575 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); |
1083 | 1576 | ||
1084 | if (!pol) | 1577 | if (!pol) |
1085 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, | 1578 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1086 | xfrm_policy_lookup); | 1579 | xfrm_policy_lookup); |
1087 | 1580 | ||
1088 | if (!pol) | 1581 | if (!pol) { |
1089 | return !skb->sp || !secpath_has_tunnel(skb->sp, 0); | 1582 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { |
1583 | xfrm_secpath_reject(xerr_idx, skb, &fl); | ||
1584 | return 0; | ||
1585 | } | ||
1586 | return 1; | ||
1587 | } | ||
1090 | 1588 | ||
1091 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; | 1589 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; |
1092 | 1590 | ||
1591 | pols[0] = pol; | ||
1592 | npols ++; | ||
1593 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1594 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1595 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1596 | &fl, family, | ||
1597 | XFRM_POLICY_IN); | ||
1598 | if (pols[1]) { | ||
1599 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; | ||
1600 | npols ++; | ||
1601 | } | ||
1602 | } | ||
1603 | #endif | ||
1604 | |||
1093 | if (pol->action == XFRM_POLICY_ALLOW) { | 1605 | if (pol->action == XFRM_POLICY_ALLOW) { |
1094 | struct sec_path *sp; | 1606 | struct sec_path *sp; |
1095 | static struct sec_path dummy; | 1607 | static struct sec_path dummy; |
1608 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; | ||
1609 | struct xfrm_tmpl *stp[XFRM_MAX_DEPTH]; | ||
1610 | struct xfrm_tmpl **tpp = tp; | ||
1611 | int ti = 0; | ||
1096 | int i, k; | 1612 | int i, k; |
1097 | 1613 | ||
1098 | if ((sp = skb->sp) == NULL) | 1614 | if ((sp = skb->sp) == NULL) |
1099 | sp = &dummy; | 1615 | sp = &dummy; |
1100 | 1616 | ||
1617 | for (pi = 0; pi < npols; pi++) { | ||
1618 | if (pols[pi] != pol && | ||
1619 | pols[pi]->action != XFRM_POLICY_ALLOW) | ||
1620 | goto reject; | ||
1621 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) | ||
1622 | goto reject_error; | ||
1623 | for (i = 0; i < pols[pi]->xfrm_nr; i++) | ||
1624 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | ||
1625 | } | ||
1626 | xfrm_nr = ti; | ||
1627 | if (npols > 1) { | ||
1628 | xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); | ||
1629 | tpp = stp; | ||
1630 | } | ||
1631 | |||
1101 | /* For each tunnel xfrm, find the first matching tmpl. | 1632 | /* For each tunnel xfrm, find the first matching tmpl. |
1102 | * For each tmpl before that, find corresponding xfrm. | 1633 | * For each tmpl before that, find corresponding xfrm. |
1103 | * Order is _important_. Later we will implement | 1634 | * Order is _important_. Later we will implement |
1104 | * some barriers, but at the moment barriers | 1635 | * some barriers, but at the moment barriers |
1105 | * are implied between each two transformations. | 1636 | * are implied between each two transformations. |
1106 | */ | 1637 | */ |
1107 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { | 1638 | for (i = xfrm_nr-1, k = 0; i >= 0; i--) { |
1108 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); | 1639 | k = xfrm_policy_ok(tpp[i], sp, k, family); |
1109 | if (k < 0) | 1640 | if (k < 0) { |
1641 | if (k < -1) | ||
1642 | /* "-2 - errored_index" returned */ | ||
1643 | xerr_idx = -(2+k); | ||
1110 | goto reject; | 1644 | goto reject; |
1645 | } | ||
1111 | } | 1646 | } |
1112 | 1647 | ||
1113 | if (secpath_has_tunnel(sp, k)) | 1648 | if (secpath_has_nontransport(sp, k, &xerr_idx)) |
1114 | goto reject; | 1649 | goto reject; |
1115 | 1650 | ||
1116 | xfrm_pol_put(pol); | 1651 | xfrm_pols_put(pols, npols); |
1117 | return 1; | 1652 | return 1; |
1118 | } | 1653 | } |
1119 | 1654 | ||
1120 | reject: | 1655 | reject: |
1121 | xfrm_pol_put(pol); | 1656 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
1657 | reject_error: | ||
1658 | xfrm_pols_put(pols, npols); | ||
1122 | return 0; | 1659 | return 0; |
1123 | } | 1660 | } |
1124 | EXPORT_SYMBOL(__xfrm_policy_check); | 1661 | EXPORT_SYMBOL(__xfrm_policy_check); |
@@ -1166,7 +1703,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) | |||
1166 | 1703 | ||
1167 | static int stale_bundle(struct dst_entry *dst) | 1704 | static int stale_bundle(struct dst_entry *dst) |
1168 | { | 1705 | { |
1169 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC); | 1706 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); |
1170 | } | 1707 | } |
1171 | 1708 | ||
1172 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 1709 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
@@ -1196,33 +1733,50 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) | |||
1196 | return dst; | 1733 | return dst; |
1197 | } | 1734 | } |
1198 | 1735 | ||
1736 | static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p) | ||
1737 | { | ||
1738 | struct dst_entry *dst, **dstp; | ||
1739 | |||
1740 | write_lock(&pol->lock); | ||
1741 | dstp = &pol->bundles; | ||
1742 | while ((dst=*dstp) != NULL) { | ||
1743 | if (func(dst)) { | ||
1744 | *dstp = dst->next; | ||
1745 | dst->next = *gc_list_p; | ||
1746 | *gc_list_p = dst; | ||
1747 | } else { | ||
1748 | dstp = &dst->next; | ||
1749 | } | ||
1750 | } | ||
1751 | write_unlock(&pol->lock); | ||
1752 | } | ||
1753 | |||
1199 | static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) | 1754 | static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) |
1200 | { | 1755 | { |
1201 | int i; | 1756 | struct dst_entry *gc_list = NULL; |
1202 | struct xfrm_policy *pol; | 1757 | int dir; |
1203 | struct dst_entry *dst, **dstp, *gc_list = NULL; | ||
1204 | 1758 | ||
1205 | read_lock_bh(&xfrm_policy_lock); | 1759 | read_lock_bh(&xfrm_policy_lock); |
1206 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { | 1760 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { |
1207 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { | 1761 | struct xfrm_policy *pol; |
1208 | write_lock(&pol->lock); | 1762 | struct hlist_node *entry; |
1209 | dstp = &pol->bundles; | 1763 | struct hlist_head *table; |
1210 | while ((dst=*dstp) != NULL) { | 1764 | int i; |
1211 | if (func(dst)) { | 1765 | |
1212 | *dstp = dst->next; | 1766 | hlist_for_each_entry(pol, entry, |
1213 | dst->next = gc_list; | 1767 | &xfrm_policy_inexact[dir], bydst) |
1214 | gc_list = dst; | 1768 | prune_one_bundle(pol, func, &gc_list); |
1215 | } else { | 1769 | |
1216 | dstp = &dst->next; | 1770 | table = xfrm_policy_bydst[dir].table; |
1217 | } | 1771 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { |
1218 | } | 1772 | hlist_for_each_entry(pol, entry, table + i, bydst) |
1219 | write_unlock(&pol->lock); | 1773 | prune_one_bundle(pol, func, &gc_list); |
1220 | } | 1774 | } |
1221 | } | 1775 | } |
1222 | read_unlock_bh(&xfrm_policy_lock); | 1776 | read_unlock_bh(&xfrm_policy_lock); |
1223 | 1777 | ||
1224 | while (gc_list) { | 1778 | while (gc_list) { |
1225 | dst = gc_list; | 1779 | struct dst_entry *dst = gc_list; |
1226 | gc_list = dst->next; | 1780 | gc_list = dst->next; |
1227 | dst_free(dst); | 1781 | dst_free(dst); |
1228 | } | 1782 | } |
@@ -1238,22 +1792,12 @@ static void __xfrm_garbage_collect(void) | |||
1238 | xfrm_prune_bundles(unused_bundle); | 1792 | xfrm_prune_bundles(unused_bundle); |
1239 | } | 1793 | } |
1240 | 1794 | ||
1241 | int xfrm_flush_bundles(void) | 1795 | static int xfrm_flush_bundles(void) |
1242 | { | 1796 | { |
1243 | xfrm_prune_bundles(stale_bundle); | 1797 | xfrm_prune_bundles(stale_bundle); |
1244 | return 0; | 1798 | return 0; |
1245 | } | 1799 | } |
1246 | 1800 | ||
1247 | static int always_true(struct dst_entry *dst) | ||
1248 | { | ||
1249 | return 1; | ||
1250 | } | ||
1251 | |||
1252 | void xfrm_flush_all_bundles(void) | ||
1253 | { | ||
1254 | xfrm_prune_bundles(always_true); | ||
1255 | } | ||
1256 | |||
1257 | void xfrm_init_pmtu(struct dst_entry *dst) | 1801 | void xfrm_init_pmtu(struct dst_entry *dst) |
1258 | { | 1802 | { |
1259 | do { | 1803 | do { |
@@ -1281,7 +1825,7 @@ EXPORT_SYMBOL(xfrm_init_pmtu); | |||
1281 | * still valid. | 1825 | * still valid. |
1282 | */ | 1826 | */ |
1283 | 1827 | ||
1284 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | 1828 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict) |
1285 | { | 1829 | { |
1286 | struct dst_entry *dst = &first->u.dst; | 1830 | struct dst_entry *dst = &first->u.dst; |
1287 | struct xfrm_dst *last; | 1831 | struct xfrm_dst *last; |
@@ -1298,8 +1842,16 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | |||
1298 | 1842 | ||
1299 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) | 1843 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) |
1300 | return 0; | 1844 | return 0; |
1845 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) | ||
1846 | return 0; | ||
1301 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | 1847 | if (dst->xfrm->km.state != XFRM_STATE_VALID) |
1302 | return 0; | 1848 | return 0; |
1849 | if (xdst->genid != dst->xfrm->genid) | ||
1850 | return 0; | ||
1851 | |||
1852 | if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL && | ||
1853 | !xfrm_state_addr_flow_check(dst->xfrm, fl, family)) | ||
1854 | return 0; | ||
1303 | 1855 | ||
1304 | mtu = dst_mtu(dst->child); | 1856 | mtu = dst_mtu(dst->child); |
1305 | if (xdst->child_mtu_cached != mtu) { | 1857 | if (xdst->child_mtu_cached != mtu) { |
@@ -1448,12 +2000,33 @@ static struct notifier_block xfrm_dev_notifier = { | |||
1448 | 2000 | ||
1449 | static void __init xfrm_policy_init(void) | 2001 | static void __init xfrm_policy_init(void) |
1450 | { | 2002 | { |
2003 | unsigned int hmask, sz; | ||
2004 | int dir; | ||
2005 | |||
1451 | xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", | 2006 | xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", |
1452 | sizeof(struct xfrm_dst), | 2007 | sizeof(struct xfrm_dst), |
1453 | 0, SLAB_HWCACHE_ALIGN, | 2008 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1454 | NULL, NULL); | 2009 | NULL, NULL); |
1455 | if (!xfrm_dst_cache) | 2010 | |
1456 | panic("XFRM: failed to allocate xfrm_dst_cache\n"); | 2011 | hmask = 8 - 1; |
2012 | sz = (hmask+1) * sizeof(struct hlist_head); | ||
2013 | |||
2014 | xfrm_policy_byidx = xfrm_hash_alloc(sz); | ||
2015 | xfrm_idx_hmask = hmask; | ||
2016 | if (!xfrm_policy_byidx) | ||
2017 | panic("XFRM: failed to allocate byidx hash\n"); | ||
2018 | |||
2019 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
2020 | struct xfrm_policy_hash *htab; | ||
2021 | |||
2022 | INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]); | ||
2023 | |||
2024 | htab = &xfrm_policy_bydst[dir]; | ||
2025 | htab->table = xfrm_hash_alloc(sz); | ||
2026 | htab->hmask = hmask; | ||
2027 | if (!htab->table) | ||
2028 | panic("XFRM: failed to allocate bydst hash\n"); | ||
2029 | } | ||
1457 | 2030 | ||
1458 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); | 2031 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); |
1459 | register_netdevice_notifier(&xfrm_dev_notifier); | 2032 | register_netdevice_notifier(&xfrm_dev_notifier); |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 0021aad5db43..9f63edd39346 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -18,8 +18,11 @@ | |||
18 | #include <linux/pfkeyv2.h> | 18 | #include <linux/pfkeyv2.h> |
19 | #include <linux/ipsec.h> | 19 | #include <linux/ipsec.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/cache.h> | ||
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
22 | 23 | ||
24 | #include "xfrm_hash.h" | ||
25 | |||
23 | struct sock *xfrm_nl; | 26 | struct sock *xfrm_nl; |
24 | EXPORT_SYMBOL(xfrm_nl); | 27 | EXPORT_SYMBOL(xfrm_nl); |
25 | 28 | ||
@@ -32,7 +35,7 @@ EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); | |||
32 | /* Each xfrm_state may be linked to two tables: | 35 | /* Each xfrm_state may be linked to two tables: |
33 | 36 | ||
34 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) | 37 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) |
35 | 2. Hash table by daddr to find what SAs exist for given | 38 | 2. Hash table by (daddr,family,reqid) to find what SAs exist for given |
36 | destination/tunnel endpoint. (output) | 39 | destination/tunnel endpoint. (output) |
37 | */ | 40 | */ |
38 | 41 | ||
@@ -44,8 +47,123 @@ static DEFINE_SPINLOCK(xfrm_state_lock); | |||
44 | * Main use is finding SA after policy selected tunnel or transport mode. | 47 | * Main use is finding SA after policy selected tunnel or transport mode. |
45 | * Also, it can be used by ah/esp icmp error handler to find offending SA. | 48 | * Also, it can be used by ah/esp icmp error handler to find offending SA. |
46 | */ | 49 | */ |
47 | static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE]; | 50 | static struct hlist_head *xfrm_state_bydst __read_mostly; |
48 | static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; | 51 | static struct hlist_head *xfrm_state_bysrc __read_mostly; |
52 | static struct hlist_head *xfrm_state_byspi __read_mostly; | ||
53 | static unsigned int xfrm_state_hmask __read_mostly; | ||
54 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | ||
55 | static unsigned int xfrm_state_num; | ||
56 | static unsigned int xfrm_state_genid; | ||
57 | |||
58 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, | ||
59 | xfrm_address_t *saddr, | ||
60 | u32 reqid, | ||
61 | unsigned short family) | ||
62 | { | ||
63 | return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); | ||
64 | } | ||
65 | |||
66 | static inline unsigned int xfrm_src_hash(xfrm_address_t *addr, | ||
67 | unsigned short family) | ||
68 | { | ||
69 | return __xfrm_src_hash(addr, family, xfrm_state_hmask); | ||
70 | } | ||
71 | |||
72 | static inline unsigned int | ||
73 | xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) | ||
74 | { | ||
75 | return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); | ||
76 | } | ||
77 | |||
78 | static void xfrm_hash_transfer(struct hlist_head *list, | ||
79 | struct hlist_head *ndsttable, | ||
80 | struct hlist_head *nsrctable, | ||
81 | struct hlist_head *nspitable, | ||
82 | unsigned int nhashmask) | ||
83 | { | ||
84 | struct hlist_node *entry, *tmp; | ||
85 | struct xfrm_state *x; | ||
86 | |||
87 | hlist_for_each_entry_safe(x, entry, tmp, list, bydst) { | ||
88 | unsigned int h; | ||
89 | |||
90 | h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, | ||
91 | x->props.reqid, x->props.family, | ||
92 | nhashmask); | ||
93 | hlist_add_head(&x->bydst, ndsttable+h); | ||
94 | |||
95 | h = __xfrm_src_hash(&x->props.saddr, x->props.family, | ||
96 | nhashmask); | ||
97 | hlist_add_head(&x->bysrc, nsrctable+h); | ||
98 | |||
99 | h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, | ||
100 | x->props.family, nhashmask); | ||
101 | hlist_add_head(&x->byspi, nspitable+h); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static unsigned long xfrm_hash_new_size(void) | ||
106 | { | ||
107 | return ((xfrm_state_hmask + 1) << 1) * | ||
108 | sizeof(struct hlist_head); | ||
109 | } | ||
110 | |||
111 | static DEFINE_MUTEX(hash_resize_mutex); | ||
112 | |||
113 | static void xfrm_hash_resize(void *__unused) | ||
114 | { | ||
115 | struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; | ||
116 | unsigned long nsize, osize; | ||
117 | unsigned int nhashmask, ohashmask; | ||
118 | int i; | ||
119 | |||
120 | mutex_lock(&hash_resize_mutex); | ||
121 | |||
122 | nsize = xfrm_hash_new_size(); | ||
123 | ndst = xfrm_hash_alloc(nsize); | ||
124 | if (!ndst) | ||
125 | goto out_unlock; | ||
126 | nsrc = xfrm_hash_alloc(nsize); | ||
127 | if (!nsrc) { | ||
128 | xfrm_hash_free(ndst, nsize); | ||
129 | goto out_unlock; | ||
130 | } | ||
131 | nspi = xfrm_hash_alloc(nsize); | ||
132 | if (!nspi) { | ||
133 | xfrm_hash_free(ndst, nsize); | ||
134 | xfrm_hash_free(nsrc, nsize); | ||
135 | goto out_unlock; | ||
136 | } | ||
137 | |||
138 | spin_lock_bh(&xfrm_state_lock); | ||
139 | |||
140 | nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; | ||
141 | for (i = xfrm_state_hmask; i >= 0; i--) | ||
142 | xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi, | ||
143 | nhashmask); | ||
144 | |||
145 | odst = xfrm_state_bydst; | ||
146 | osrc = xfrm_state_bysrc; | ||
147 | ospi = xfrm_state_byspi; | ||
148 | ohashmask = xfrm_state_hmask; | ||
149 | |||
150 | xfrm_state_bydst = ndst; | ||
151 | xfrm_state_bysrc = nsrc; | ||
152 | xfrm_state_byspi = nspi; | ||
153 | xfrm_state_hmask = nhashmask; | ||
154 | |||
155 | spin_unlock_bh(&xfrm_state_lock); | ||
156 | |||
157 | osize = (ohashmask + 1) * sizeof(struct hlist_head); | ||
158 | xfrm_hash_free(odst, osize); | ||
159 | xfrm_hash_free(osrc, osize); | ||
160 | xfrm_hash_free(ospi, osize); | ||
161 | |||
162 | out_unlock: | ||
163 | mutex_unlock(&hash_resize_mutex); | ||
164 | } | ||
165 | |||
166 | static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); | ||
49 | 167 | ||
50 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); | 168 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); |
51 | EXPORT_SYMBOL(km_waitq); | 169 | EXPORT_SYMBOL(km_waitq); |
@@ -54,11 +172,9 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock); | |||
54 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; | 172 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; |
55 | 173 | ||
56 | static struct work_struct xfrm_state_gc_work; | 174 | static struct work_struct xfrm_state_gc_work; |
57 | static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list); | 175 | static HLIST_HEAD(xfrm_state_gc_list); |
58 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); | 176 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); |
59 | 177 | ||
60 | static int xfrm_state_gc_flush_bundles; | ||
61 | |||
62 | int __xfrm_state_delete(struct xfrm_state *x); | 178 | int __xfrm_state_delete(struct xfrm_state *x); |
63 | 179 | ||
64 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | 180 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); |
@@ -69,14 +185,13 @@ void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | |||
69 | 185 | ||
70 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 186 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
71 | { | 187 | { |
72 | if (del_timer(&x->timer)) | 188 | del_timer_sync(&x->timer); |
73 | BUG(); | 189 | del_timer_sync(&x->rtimer); |
74 | if (del_timer(&x->rtimer)) | ||
75 | BUG(); | ||
76 | kfree(x->aalg); | 190 | kfree(x->aalg); |
77 | kfree(x->ealg); | 191 | kfree(x->ealg); |
78 | kfree(x->calg); | 192 | kfree(x->calg); |
79 | kfree(x->encap); | 193 | kfree(x->encap); |
194 | kfree(x->coaddr); | ||
80 | if (x->mode) | 195 | if (x->mode) |
81 | xfrm_put_mode(x->mode); | 196 | xfrm_put_mode(x->mode); |
82 | if (x->type) { | 197 | if (x->type) { |
@@ -90,22 +205,17 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
90 | static void xfrm_state_gc_task(void *data) | 205 | static void xfrm_state_gc_task(void *data) |
91 | { | 206 | { |
92 | struct xfrm_state *x; | 207 | struct xfrm_state *x; |
93 | struct list_head *entry, *tmp; | 208 | struct hlist_node *entry, *tmp; |
94 | struct list_head gc_list = LIST_HEAD_INIT(gc_list); | 209 | struct hlist_head gc_list; |
95 | |||
96 | if (xfrm_state_gc_flush_bundles) { | ||
97 | xfrm_state_gc_flush_bundles = 0; | ||
98 | xfrm_flush_bundles(); | ||
99 | } | ||
100 | 210 | ||
101 | spin_lock_bh(&xfrm_state_gc_lock); | 211 | spin_lock_bh(&xfrm_state_gc_lock); |
102 | list_splice_init(&xfrm_state_gc_list, &gc_list); | 212 | gc_list.first = xfrm_state_gc_list.first; |
213 | INIT_HLIST_HEAD(&xfrm_state_gc_list); | ||
103 | spin_unlock_bh(&xfrm_state_gc_lock); | 214 | spin_unlock_bh(&xfrm_state_gc_lock); |
104 | 215 | ||
105 | list_for_each_safe(entry, tmp, &gc_list) { | 216 | hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) |
106 | x = list_entry(entry, struct xfrm_state, bydst); | ||
107 | xfrm_state_gc_destroy(x); | 217 | xfrm_state_gc_destroy(x); |
108 | } | 218 | |
109 | wake_up(&km_waitq); | 219 | wake_up(&km_waitq); |
110 | } | 220 | } |
111 | 221 | ||
@@ -168,9 +278,9 @@ static void xfrm_timer_handler(unsigned long data) | |||
168 | if (warn) | 278 | if (warn) |
169 | km_state_expired(x, 0, 0); | 279 | km_state_expired(x, 0, 0); |
170 | resched: | 280 | resched: |
171 | if (next != LONG_MAX && | 281 | if (next != LONG_MAX) |
172 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) | 282 | mod_timer(&x->timer, jiffies + make_jiffies(next)); |
173 | xfrm_state_hold(x); | 283 | |
174 | goto out; | 284 | goto out; |
175 | 285 | ||
176 | expired: | 286 | expired: |
@@ -185,7 +295,6 @@ expired: | |||
185 | 295 | ||
186 | out: | 296 | out: |
187 | spin_unlock(&x->lock); | 297 | spin_unlock(&x->lock); |
188 | xfrm_state_put(x); | ||
189 | } | 298 | } |
190 | 299 | ||
191 | static void xfrm_replay_timer_handler(unsigned long data); | 300 | static void xfrm_replay_timer_handler(unsigned long data); |
@@ -199,8 +308,9 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
199 | if (x) { | 308 | if (x) { |
200 | atomic_set(&x->refcnt, 1); | 309 | atomic_set(&x->refcnt, 1); |
201 | atomic_set(&x->tunnel_users, 0); | 310 | atomic_set(&x->tunnel_users, 0); |
202 | INIT_LIST_HEAD(&x->bydst); | 311 | INIT_HLIST_NODE(&x->bydst); |
203 | INIT_LIST_HEAD(&x->byspi); | 312 | INIT_HLIST_NODE(&x->bysrc); |
313 | INIT_HLIST_NODE(&x->byspi); | ||
204 | init_timer(&x->timer); | 314 | init_timer(&x->timer); |
205 | x->timer.function = xfrm_timer_handler; | 315 | x->timer.function = xfrm_timer_handler; |
206 | x->timer.data = (unsigned long)x; | 316 | x->timer.data = (unsigned long)x; |
@@ -225,7 +335,7 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
225 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); | 335 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); |
226 | 336 | ||
227 | spin_lock_bh(&xfrm_state_gc_lock); | 337 | spin_lock_bh(&xfrm_state_gc_lock); |
228 | list_add(&x->bydst, &xfrm_state_gc_list); | 338 | hlist_add_head(&x->bydst, &xfrm_state_gc_list); |
229 | spin_unlock_bh(&xfrm_state_gc_lock); | 339 | spin_unlock_bh(&xfrm_state_gc_lock); |
230 | schedule_work(&xfrm_state_gc_work); | 340 | schedule_work(&xfrm_state_gc_work); |
231 | } | 341 | } |
@@ -238,27 +348,12 @@ int __xfrm_state_delete(struct xfrm_state *x) | |||
238 | if (x->km.state != XFRM_STATE_DEAD) { | 348 | if (x->km.state != XFRM_STATE_DEAD) { |
239 | x->km.state = XFRM_STATE_DEAD; | 349 | x->km.state = XFRM_STATE_DEAD; |
240 | spin_lock(&xfrm_state_lock); | 350 | spin_lock(&xfrm_state_lock); |
241 | list_del(&x->bydst); | 351 | hlist_del(&x->bydst); |
242 | __xfrm_state_put(x); | 352 | hlist_del(&x->bysrc); |
243 | if (x->id.spi) { | 353 | if (x->id.spi) |
244 | list_del(&x->byspi); | 354 | hlist_del(&x->byspi); |
245 | __xfrm_state_put(x); | 355 | xfrm_state_num--; |
246 | } | ||
247 | spin_unlock(&xfrm_state_lock); | 356 | spin_unlock(&xfrm_state_lock); |
248 | if (del_timer(&x->timer)) | ||
249 | __xfrm_state_put(x); | ||
250 | if (del_timer(&x->rtimer)) | ||
251 | __xfrm_state_put(x); | ||
252 | |||
253 | /* The number two in this test is the reference | ||
254 | * mentioned in the comment below plus the reference | ||
255 | * our caller holds. A larger value means that | ||
256 | * there are DSTs attached to this xfrm_state. | ||
257 | */ | ||
258 | if (atomic_read(&x->refcnt) > 2) { | ||
259 | xfrm_state_gc_flush_bundles = 1; | ||
260 | schedule_work(&xfrm_state_gc_work); | ||
261 | } | ||
262 | 357 | ||
263 | /* All xfrm_state objects are created by xfrm_state_alloc. | 358 | /* All xfrm_state objects are created by xfrm_state_alloc. |
264 | * The xfrm_state_alloc call gives a reference, and that | 359 | * The xfrm_state_alloc call gives a reference, and that |
@@ -287,14 +382,15 @@ EXPORT_SYMBOL(xfrm_state_delete); | |||
287 | void xfrm_state_flush(u8 proto) | 382 | void xfrm_state_flush(u8 proto) |
288 | { | 383 | { |
289 | int i; | 384 | int i; |
290 | struct xfrm_state *x; | ||
291 | 385 | ||
292 | spin_lock_bh(&xfrm_state_lock); | 386 | spin_lock_bh(&xfrm_state_lock); |
293 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 387 | for (i = 0; i <= xfrm_state_hmask; i++) { |
388 | struct hlist_node *entry; | ||
389 | struct xfrm_state *x; | ||
294 | restart: | 390 | restart: |
295 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 391 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { |
296 | if (!xfrm_state_kern(x) && | 392 | if (!xfrm_state_kern(x) && |
297 | (proto == IPSEC_PROTO_ANY || x->id.proto == proto)) { | 393 | xfrm_id_proto_match(x->id.proto, proto)) { |
298 | xfrm_state_hold(x); | 394 | xfrm_state_hold(x); |
299 | spin_unlock_bh(&xfrm_state_lock); | 395 | spin_unlock_bh(&xfrm_state_lock); |
300 | 396 | ||
@@ -325,29 +421,103 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
325 | return 0; | 421 | return 0; |
326 | } | 422 | } |
327 | 423 | ||
424 | static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) | ||
425 | { | ||
426 | unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); | ||
427 | struct xfrm_state *x; | ||
428 | struct hlist_node *entry; | ||
429 | |||
430 | hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) { | ||
431 | if (x->props.family != family || | ||
432 | x->id.spi != spi || | ||
433 | x->id.proto != proto) | ||
434 | continue; | ||
435 | |||
436 | switch (family) { | ||
437 | case AF_INET: | ||
438 | if (x->id.daddr.a4 != daddr->a4) | ||
439 | continue; | ||
440 | break; | ||
441 | case AF_INET6: | ||
442 | if (!ipv6_addr_equal((struct in6_addr *)daddr, | ||
443 | (struct in6_addr *) | ||
444 | x->id.daddr.a6)) | ||
445 | continue; | ||
446 | break; | ||
447 | }; | ||
448 | |||
449 | xfrm_state_hold(x); | ||
450 | return x; | ||
451 | } | ||
452 | |||
453 | return NULL; | ||
454 | } | ||
455 | |||
456 | static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) | ||
457 | { | ||
458 | unsigned int h = xfrm_src_hash(saddr, family); | ||
459 | struct xfrm_state *x; | ||
460 | struct hlist_node *entry; | ||
461 | |||
462 | hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { | ||
463 | if (x->props.family != family || | ||
464 | x->id.proto != proto) | ||
465 | continue; | ||
466 | |||
467 | switch (family) { | ||
468 | case AF_INET: | ||
469 | if (x->id.daddr.a4 != daddr->a4 || | ||
470 | x->props.saddr.a4 != saddr->a4) | ||
471 | continue; | ||
472 | break; | ||
473 | case AF_INET6: | ||
474 | if (!ipv6_addr_equal((struct in6_addr *)daddr, | ||
475 | (struct in6_addr *) | ||
476 | x->id.daddr.a6) || | ||
477 | !ipv6_addr_equal((struct in6_addr *)saddr, | ||
478 | (struct in6_addr *) | ||
479 | x->props.saddr.a6)) | ||
480 | continue; | ||
481 | break; | ||
482 | }; | ||
483 | |||
484 | xfrm_state_hold(x); | ||
485 | return x; | ||
486 | } | ||
487 | |||
488 | return NULL; | ||
489 | } | ||
490 | |||
491 | static inline struct xfrm_state * | ||
492 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | ||
493 | { | ||
494 | if (use_spi) | ||
495 | return __xfrm_state_lookup(&x->id.daddr, x->id.spi, | ||
496 | x->id.proto, family); | ||
497 | else | ||
498 | return __xfrm_state_lookup_byaddr(&x->id.daddr, | ||
499 | &x->props.saddr, | ||
500 | x->id.proto, family); | ||
501 | } | ||
502 | |||
328 | struct xfrm_state * | 503 | struct xfrm_state * |
329 | xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | 504 | xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, |
330 | struct flowi *fl, struct xfrm_tmpl *tmpl, | 505 | struct flowi *fl, struct xfrm_tmpl *tmpl, |
331 | struct xfrm_policy *pol, int *err, | 506 | struct xfrm_policy *pol, int *err, |
332 | unsigned short family) | 507 | unsigned short family) |
333 | { | 508 | { |
334 | unsigned h = xfrm_dst_hash(daddr, family); | 509 | unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); |
510 | struct hlist_node *entry; | ||
335 | struct xfrm_state *x, *x0; | 511 | struct xfrm_state *x, *x0; |
336 | int acquire_in_progress = 0; | 512 | int acquire_in_progress = 0; |
337 | int error = 0; | 513 | int error = 0; |
338 | struct xfrm_state *best = NULL; | 514 | struct xfrm_state *best = NULL; |
339 | struct xfrm_state_afinfo *afinfo; | ||
340 | 515 | ||
341 | afinfo = xfrm_state_get_afinfo(family); | ||
342 | if (afinfo == NULL) { | ||
343 | *err = -EAFNOSUPPORT; | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | spin_lock_bh(&xfrm_state_lock); | 516 | spin_lock_bh(&xfrm_state_lock); |
348 | list_for_each_entry(x, xfrm_state_bydst+h, bydst) { | 517 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { |
349 | if (x->props.family == family && | 518 | if (x->props.family == family && |
350 | x->props.reqid == tmpl->reqid && | 519 | x->props.reqid == tmpl->reqid && |
520 | !(x->props.flags & XFRM_STATE_WILDRECV) && | ||
351 | xfrm_state_addr_check(x, daddr, saddr, family) && | 521 | xfrm_state_addr_check(x, daddr, saddr, family) && |
352 | tmpl->mode == x->props.mode && | 522 | tmpl->mode == x->props.mode && |
353 | tmpl->id.proto == x->id.proto && | 523 | tmpl->id.proto == x->id.proto && |
@@ -367,7 +537,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
367 | */ | 537 | */ |
368 | if (x->km.state == XFRM_STATE_VALID) { | 538 | if (x->km.state == XFRM_STATE_VALID) { |
369 | if (!xfrm_selector_match(&x->sel, fl, family) || | 539 | if (!xfrm_selector_match(&x->sel, fl, family) || |
370 | !xfrm_sec_ctx_match(pol->security, x->security)) | 540 | !security_xfrm_state_pol_flow_match(x, pol, fl)) |
371 | continue; | 541 | continue; |
372 | if (!best || | 542 | if (!best || |
373 | best->km.dying > x->km.dying || | 543 | best->km.dying > x->km.dying || |
@@ -379,7 +549,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
379 | } else if (x->km.state == XFRM_STATE_ERROR || | 549 | } else if (x->km.state == XFRM_STATE_ERROR || |
380 | x->km.state == XFRM_STATE_EXPIRED) { | 550 | x->km.state == XFRM_STATE_EXPIRED) { |
381 | if (xfrm_selector_match(&x->sel, fl, family) && | 551 | if (xfrm_selector_match(&x->sel, fl, family) && |
382 | xfrm_sec_ctx_match(pol->security, x->security)) | 552 | security_xfrm_state_pol_flow_match(x, pol, fl)) |
383 | error = -ESRCH; | 553 | error = -ESRCH; |
384 | } | 554 | } |
385 | } | 555 | } |
@@ -388,8 +558,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
388 | x = best; | 558 | x = best; |
389 | if (!x && !error && !acquire_in_progress) { | 559 | if (!x && !error && !acquire_in_progress) { |
390 | if (tmpl->id.spi && | 560 | if (tmpl->id.spi && |
391 | (x0 = afinfo->state_lookup(daddr, tmpl->id.spi, | 561 | (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, |
392 | tmpl->id.proto)) != NULL) { | 562 | tmpl->id.proto, family)) != NULL) { |
393 | xfrm_state_put(x0); | 563 | xfrm_state_put(x0); |
394 | error = -EEXIST; | 564 | error = -EEXIST; |
395 | goto out; | 565 | goto out; |
@@ -403,17 +573,24 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
403 | * to current session. */ | 573 | * to current session. */ |
404 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 574 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
405 | 575 | ||
576 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | ||
577 | if (error) { | ||
578 | x->km.state = XFRM_STATE_DEAD; | ||
579 | xfrm_state_put(x); | ||
580 | x = NULL; | ||
581 | goto out; | ||
582 | } | ||
583 | |||
406 | if (km_query(x, tmpl, pol) == 0) { | 584 | if (km_query(x, tmpl, pol) == 0) { |
407 | x->km.state = XFRM_STATE_ACQ; | 585 | x->km.state = XFRM_STATE_ACQ; |
408 | list_add_tail(&x->bydst, xfrm_state_bydst+h); | 586 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
409 | xfrm_state_hold(x); | 587 | h = xfrm_src_hash(saddr, family); |
588 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | ||
410 | if (x->id.spi) { | 589 | if (x->id.spi) { |
411 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); | 590 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); |
412 | list_add(&x->byspi, xfrm_state_byspi+h); | 591 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
413 | xfrm_state_hold(x); | ||
414 | } | 592 | } |
415 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | 593 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; |
416 | xfrm_state_hold(x); | ||
417 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | 594 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; |
418 | add_timer(&x->timer); | 595 | add_timer(&x->timer); |
419 | } else { | 596 | } else { |
@@ -429,59 +606,167 @@ out: | |||
429 | else | 606 | else |
430 | *err = acquire_in_progress ? -EAGAIN : error; | 607 | *err = acquire_in_progress ? -EAGAIN : error; |
431 | spin_unlock_bh(&xfrm_state_lock); | 608 | spin_unlock_bh(&xfrm_state_lock); |
432 | xfrm_state_put_afinfo(afinfo); | ||
433 | return x; | 609 | return x; |
434 | } | 610 | } |
435 | 611 | ||
436 | static void __xfrm_state_insert(struct xfrm_state *x) | 612 | static void __xfrm_state_insert(struct xfrm_state *x) |
437 | { | 613 | { |
438 | unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family); | 614 | unsigned int h; |
439 | 615 | ||
440 | list_add(&x->bydst, xfrm_state_bydst+h); | 616 | x->genid = ++xfrm_state_genid; |
441 | xfrm_state_hold(x); | ||
442 | 617 | ||
443 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 618 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, |
619 | x->props.reqid, x->props.family); | ||
620 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | ||
444 | 621 | ||
445 | list_add(&x->byspi, xfrm_state_byspi+h); | 622 | h = xfrm_src_hash(&x->props.saddr, x->props.family); |
446 | xfrm_state_hold(x); | 623 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
447 | 624 | ||
448 | if (!mod_timer(&x->timer, jiffies + HZ)) | 625 | if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) { |
449 | xfrm_state_hold(x); | 626 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, |
627 | x->props.family); | ||
450 | 628 | ||
451 | if (x->replay_maxage && | 629 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
452 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | 630 | } |
453 | xfrm_state_hold(x); | 631 | |
632 | mod_timer(&x->timer, jiffies + HZ); | ||
633 | if (x->replay_maxage) | ||
634 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | ||
454 | 635 | ||
455 | wake_up(&km_waitq); | 636 | wake_up(&km_waitq); |
637 | |||
638 | xfrm_state_num++; | ||
639 | |||
640 | if (x->bydst.next != NULL && | ||
641 | (xfrm_state_hmask + 1) < xfrm_state_hashmax && | ||
642 | xfrm_state_num > xfrm_state_hmask) | ||
643 | schedule_work(&xfrm_hash_work); | ||
644 | } | ||
645 | |||
646 | /* xfrm_state_lock is held */ | ||
647 | static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | ||
648 | { | ||
649 | unsigned short family = xnew->props.family; | ||
650 | u32 reqid = xnew->props.reqid; | ||
651 | struct xfrm_state *x; | ||
652 | struct hlist_node *entry; | ||
653 | unsigned int h; | ||
654 | |||
655 | h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); | ||
656 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | ||
657 | if (x->props.family == family && | ||
658 | x->props.reqid == reqid && | ||
659 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | ||
660 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | ||
661 | x->genid = xfrm_state_genid; | ||
662 | } | ||
456 | } | 663 | } |
457 | 664 | ||
458 | void xfrm_state_insert(struct xfrm_state *x) | 665 | void xfrm_state_insert(struct xfrm_state *x) |
459 | { | 666 | { |
460 | spin_lock_bh(&xfrm_state_lock); | 667 | spin_lock_bh(&xfrm_state_lock); |
668 | __xfrm_state_bump_genids(x); | ||
461 | __xfrm_state_insert(x); | 669 | __xfrm_state_insert(x); |
462 | spin_unlock_bh(&xfrm_state_lock); | 670 | spin_unlock_bh(&xfrm_state_lock); |
463 | |||
464 | xfrm_flush_all_bundles(); | ||
465 | } | 671 | } |
466 | EXPORT_SYMBOL(xfrm_state_insert); | 672 | EXPORT_SYMBOL(xfrm_state_insert); |
467 | 673 | ||
674 | /* xfrm_state_lock is held */ | ||
675 | static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) | ||
676 | { | ||
677 | unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); | ||
678 | struct hlist_node *entry; | ||
679 | struct xfrm_state *x; | ||
680 | |||
681 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | ||
682 | if (x->props.reqid != reqid || | ||
683 | x->props.mode != mode || | ||
684 | x->props.family != family || | ||
685 | x->km.state != XFRM_STATE_ACQ || | ||
686 | x->id.spi != 0) | ||
687 | continue; | ||
688 | |||
689 | switch (family) { | ||
690 | case AF_INET: | ||
691 | if (x->id.daddr.a4 != daddr->a4 || | ||
692 | x->props.saddr.a4 != saddr->a4) | ||
693 | continue; | ||
694 | break; | ||
695 | case AF_INET6: | ||
696 | if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, | ||
697 | (struct in6_addr *)daddr) || | ||
698 | !ipv6_addr_equal((struct in6_addr *) | ||
699 | x->props.saddr.a6, | ||
700 | (struct in6_addr *)saddr)) | ||
701 | continue; | ||
702 | break; | ||
703 | }; | ||
704 | |||
705 | xfrm_state_hold(x); | ||
706 | return x; | ||
707 | } | ||
708 | |||
709 | if (!create) | ||
710 | return NULL; | ||
711 | |||
712 | x = xfrm_state_alloc(); | ||
713 | if (likely(x)) { | ||
714 | switch (family) { | ||
715 | case AF_INET: | ||
716 | x->sel.daddr.a4 = daddr->a4; | ||
717 | x->sel.saddr.a4 = saddr->a4; | ||
718 | x->sel.prefixlen_d = 32; | ||
719 | x->sel.prefixlen_s = 32; | ||
720 | x->props.saddr.a4 = saddr->a4; | ||
721 | x->id.daddr.a4 = daddr->a4; | ||
722 | break; | ||
723 | |||
724 | case AF_INET6: | ||
725 | ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, | ||
726 | (struct in6_addr *)daddr); | ||
727 | ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, | ||
728 | (struct in6_addr *)saddr); | ||
729 | x->sel.prefixlen_d = 128; | ||
730 | x->sel.prefixlen_s = 128; | ||
731 | ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, | ||
732 | (struct in6_addr *)saddr); | ||
733 | ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, | ||
734 | (struct in6_addr *)daddr); | ||
735 | break; | ||
736 | }; | ||
737 | |||
738 | x->km.state = XFRM_STATE_ACQ; | ||
739 | x->id.proto = proto; | ||
740 | x->props.family = family; | ||
741 | x->props.mode = mode; | ||
742 | x->props.reqid = reqid; | ||
743 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | ||
744 | xfrm_state_hold(x); | ||
745 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | ||
746 | add_timer(&x->timer); | ||
747 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | ||
748 | h = xfrm_src_hash(saddr, family); | ||
749 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | ||
750 | wake_up(&km_waitq); | ||
751 | } | ||
752 | |||
753 | return x; | ||
754 | } | ||
755 | |||
468 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); | 756 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); |
469 | 757 | ||
470 | int xfrm_state_add(struct xfrm_state *x) | 758 | int xfrm_state_add(struct xfrm_state *x) |
471 | { | 759 | { |
472 | struct xfrm_state_afinfo *afinfo; | ||
473 | struct xfrm_state *x1; | 760 | struct xfrm_state *x1; |
474 | int family; | 761 | int family; |
475 | int err; | 762 | int err; |
763 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | ||
476 | 764 | ||
477 | family = x->props.family; | 765 | family = x->props.family; |
478 | afinfo = xfrm_state_get_afinfo(family); | ||
479 | if (unlikely(afinfo == NULL)) | ||
480 | return -EAFNOSUPPORT; | ||
481 | 766 | ||
482 | spin_lock_bh(&xfrm_state_lock); | 767 | spin_lock_bh(&xfrm_state_lock); |
483 | 768 | ||
484 | x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | 769 | x1 = __xfrm_state_locate(x, use_spi, family); |
485 | if (x1) { | 770 | if (x1) { |
486 | xfrm_state_put(x1); | 771 | xfrm_state_put(x1); |
487 | x1 = NULL; | 772 | x1 = NULL; |
@@ -489,7 +774,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
489 | goto out; | 774 | goto out; |
490 | } | 775 | } |
491 | 776 | ||
492 | if (x->km.seq) { | 777 | if (use_spi && x->km.seq) { |
493 | x1 = __xfrm_find_acq_byseq(x->km.seq); | 778 | x1 = __xfrm_find_acq_byseq(x->km.seq); |
494 | if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { | 779 | if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { |
495 | xfrm_state_put(x1); | 780 | xfrm_state_put(x1); |
@@ -497,20 +782,17 @@ int xfrm_state_add(struct xfrm_state *x) | |||
497 | } | 782 | } |
498 | } | 783 | } |
499 | 784 | ||
500 | if (!x1) | 785 | if (use_spi && !x1) |
501 | x1 = afinfo->find_acq( | 786 | x1 = __find_acq_core(family, x->props.mode, x->props.reqid, |
502 | x->props.mode, x->props.reqid, x->id.proto, | 787 | x->id.proto, |
503 | &x->id.daddr, &x->props.saddr, 0); | 788 | &x->id.daddr, &x->props.saddr, 0); |
504 | 789 | ||
790 | __xfrm_state_bump_genids(x); | ||
505 | __xfrm_state_insert(x); | 791 | __xfrm_state_insert(x); |
506 | err = 0; | 792 | err = 0; |
507 | 793 | ||
508 | out: | 794 | out: |
509 | spin_unlock_bh(&xfrm_state_lock); | 795 | spin_unlock_bh(&xfrm_state_lock); |
510 | xfrm_state_put_afinfo(afinfo); | ||
511 | |||
512 | if (!err) | ||
513 | xfrm_flush_all_bundles(); | ||
514 | 796 | ||
515 | if (x1) { | 797 | if (x1) { |
516 | xfrm_state_delete(x1); | 798 | xfrm_state_delete(x1); |
@@ -523,16 +805,12 @@ EXPORT_SYMBOL(xfrm_state_add); | |||
523 | 805 | ||
524 | int xfrm_state_update(struct xfrm_state *x) | 806 | int xfrm_state_update(struct xfrm_state *x) |
525 | { | 807 | { |
526 | struct xfrm_state_afinfo *afinfo; | ||
527 | struct xfrm_state *x1; | 808 | struct xfrm_state *x1; |
528 | int err; | 809 | int err; |
529 | 810 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | |
530 | afinfo = xfrm_state_get_afinfo(x->props.family); | ||
531 | if (unlikely(afinfo == NULL)) | ||
532 | return -EAFNOSUPPORT; | ||
533 | 811 | ||
534 | spin_lock_bh(&xfrm_state_lock); | 812 | spin_lock_bh(&xfrm_state_lock); |
535 | x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | 813 | x1 = __xfrm_state_locate(x, use_spi, x->props.family); |
536 | 814 | ||
537 | err = -ESRCH; | 815 | err = -ESRCH; |
538 | if (!x1) | 816 | if (!x1) |
@@ -552,7 +830,6 @@ int xfrm_state_update(struct xfrm_state *x) | |||
552 | 830 | ||
553 | out: | 831 | out: |
554 | spin_unlock_bh(&xfrm_state_lock); | 832 | spin_unlock_bh(&xfrm_state_lock); |
555 | xfrm_state_put_afinfo(afinfo); | ||
556 | 833 | ||
557 | if (err) | 834 | if (err) |
558 | return err; | 835 | return err; |
@@ -568,11 +845,15 @@ out: | |||
568 | if (likely(x1->km.state == XFRM_STATE_VALID)) { | 845 | if (likely(x1->km.state == XFRM_STATE_VALID)) { |
569 | if (x->encap && x1->encap) | 846 | if (x->encap && x1->encap) |
570 | memcpy(x1->encap, x->encap, sizeof(*x1->encap)); | 847 | memcpy(x1->encap, x->encap, sizeof(*x1->encap)); |
848 | if (x->coaddr && x1->coaddr) { | ||
849 | memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); | ||
850 | } | ||
851 | if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) | ||
852 | memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); | ||
571 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); | 853 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); |
572 | x1->km.dying = 0; | 854 | x1->km.dying = 0; |
573 | 855 | ||
574 | if (!mod_timer(&x1->timer, jiffies + HZ)) | 856 | mod_timer(&x1->timer, jiffies + HZ); |
575 | xfrm_state_hold(x1); | ||
576 | if (x1->curlft.use_time) | 857 | if (x1->curlft.use_time) |
577 | xfrm_state_check_expire(x1); | 858 | xfrm_state_check_expire(x1); |
578 | 859 | ||
@@ -597,8 +878,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
597 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 878 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
598 | x->curlft.packets >= x->lft.hard_packet_limit) { | 879 | x->curlft.packets >= x->lft.hard_packet_limit) { |
599 | x->km.state = XFRM_STATE_EXPIRED; | 880 | x->km.state = XFRM_STATE_EXPIRED; |
600 | if (!mod_timer(&x->timer, jiffies)) | 881 | mod_timer(&x->timer, jiffies); |
601 | xfrm_state_hold(x); | ||
602 | return -EINVAL; | 882 | return -EINVAL; |
603 | } | 883 | } |
604 | 884 | ||
@@ -640,46 +920,93 @@ xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, | |||
640 | unsigned short family) | 920 | unsigned short family) |
641 | { | 921 | { |
642 | struct xfrm_state *x; | 922 | struct xfrm_state *x; |
643 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
644 | if (!afinfo) | ||
645 | return NULL; | ||
646 | 923 | ||
647 | spin_lock_bh(&xfrm_state_lock); | 924 | spin_lock_bh(&xfrm_state_lock); |
648 | x = afinfo->state_lookup(daddr, spi, proto); | 925 | x = __xfrm_state_lookup(daddr, spi, proto, family); |
649 | spin_unlock_bh(&xfrm_state_lock); | 926 | spin_unlock_bh(&xfrm_state_lock); |
650 | xfrm_state_put_afinfo(afinfo); | ||
651 | return x; | 927 | return x; |
652 | } | 928 | } |
653 | EXPORT_SYMBOL(xfrm_state_lookup); | 929 | EXPORT_SYMBOL(xfrm_state_lookup); |
654 | 930 | ||
655 | struct xfrm_state * | 931 | struct xfrm_state * |
932 | xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
933 | u8 proto, unsigned short family) | ||
934 | { | ||
935 | struct xfrm_state *x; | ||
936 | |||
937 | spin_lock_bh(&xfrm_state_lock); | ||
938 | x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); | ||
939 | spin_unlock_bh(&xfrm_state_lock); | ||
940 | return x; | ||
941 | } | ||
942 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | ||
943 | |||
944 | struct xfrm_state * | ||
656 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | 945 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, |
657 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 946 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
658 | int create, unsigned short family) | 947 | int create, unsigned short family) |
659 | { | 948 | { |
660 | struct xfrm_state *x; | 949 | struct xfrm_state *x; |
950 | |||
951 | spin_lock_bh(&xfrm_state_lock); | ||
952 | x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); | ||
953 | spin_unlock_bh(&xfrm_state_lock); | ||
954 | |||
955 | return x; | ||
956 | } | ||
957 | EXPORT_SYMBOL(xfrm_find_acq); | ||
958 | |||
959 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
960 | int | ||
961 | xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, | ||
962 | unsigned short family) | ||
963 | { | ||
964 | int err = 0; | ||
661 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | 965 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
662 | if (!afinfo) | 966 | if (!afinfo) |
663 | return NULL; | 967 | return -EAFNOSUPPORT; |
664 | 968 | ||
665 | spin_lock_bh(&xfrm_state_lock); | 969 | spin_lock_bh(&xfrm_state_lock); |
666 | x = afinfo->find_acq(mode, reqid, proto, daddr, saddr, create); | 970 | if (afinfo->tmpl_sort) |
971 | err = afinfo->tmpl_sort(dst, src, n); | ||
667 | spin_unlock_bh(&xfrm_state_lock); | 972 | spin_unlock_bh(&xfrm_state_lock); |
668 | xfrm_state_put_afinfo(afinfo); | 973 | xfrm_state_put_afinfo(afinfo); |
669 | return x; | 974 | return err; |
670 | } | 975 | } |
671 | EXPORT_SYMBOL(xfrm_find_acq); | 976 | EXPORT_SYMBOL(xfrm_tmpl_sort); |
977 | |||
978 | int | ||
979 | xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, | ||
980 | unsigned short family) | ||
981 | { | ||
982 | int err = 0; | ||
983 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
984 | if (!afinfo) | ||
985 | return -EAFNOSUPPORT; | ||
986 | |||
987 | spin_lock_bh(&xfrm_state_lock); | ||
988 | if (afinfo->state_sort) | ||
989 | err = afinfo->state_sort(dst, src, n); | ||
990 | spin_unlock_bh(&xfrm_state_lock); | ||
991 | xfrm_state_put_afinfo(afinfo); | ||
992 | return err; | ||
993 | } | ||
994 | EXPORT_SYMBOL(xfrm_state_sort); | ||
995 | #endif | ||
672 | 996 | ||
673 | /* Silly enough, but I'm lazy to build resolution list */ | 997 | /* Silly enough, but I'm lazy to build resolution list */ |
674 | 998 | ||
675 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) | 999 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) |
676 | { | 1000 | { |
677 | int i; | 1001 | int i; |
678 | struct xfrm_state *x; | ||
679 | 1002 | ||
680 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 1003 | for (i = 0; i <= xfrm_state_hmask; i++) { |
681 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 1004 | struct hlist_node *entry; |
682 | if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) { | 1005 | struct xfrm_state *x; |
1006 | |||
1007 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { | ||
1008 | if (x->km.seq == seq && | ||
1009 | x->km.state == XFRM_STATE_ACQ) { | ||
683 | xfrm_state_hold(x); | 1010 | xfrm_state_hold(x); |
684 | return x; | 1011 | return x; |
685 | } | 1012 | } |
@@ -715,7 +1042,7 @@ EXPORT_SYMBOL(xfrm_get_acqseq); | |||
715 | void | 1042 | void |
716 | xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) | 1043 | xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) |
717 | { | 1044 | { |
718 | u32 h; | 1045 | unsigned int h; |
719 | struct xfrm_state *x0; | 1046 | struct xfrm_state *x0; |
720 | 1047 | ||
721 | if (x->id.spi) | 1048 | if (x->id.spi) |
@@ -745,8 +1072,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) | |||
745 | if (x->id.spi) { | 1072 | if (x->id.spi) { |
746 | spin_lock_bh(&xfrm_state_lock); | 1073 | spin_lock_bh(&xfrm_state_lock); |
747 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 1074 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); |
748 | list_add(&x->byspi, xfrm_state_byspi+h); | 1075 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
749 | xfrm_state_hold(x); | ||
750 | spin_unlock_bh(&xfrm_state_lock); | 1076 | spin_unlock_bh(&xfrm_state_lock); |
751 | wake_up(&km_waitq); | 1077 | wake_up(&km_waitq); |
752 | } | 1078 | } |
@@ -758,13 +1084,14 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | |||
758 | { | 1084 | { |
759 | int i; | 1085 | int i; |
760 | struct xfrm_state *x; | 1086 | struct xfrm_state *x; |
1087 | struct hlist_node *entry; | ||
761 | int count = 0; | 1088 | int count = 0; |
762 | int err = 0; | 1089 | int err = 0; |
763 | 1090 | ||
764 | spin_lock_bh(&xfrm_state_lock); | 1091 | spin_lock_bh(&xfrm_state_lock); |
765 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 1092 | for (i = 0; i <= xfrm_state_hmask; i++) { |
766 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 1093 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { |
767 | if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) | 1094 | if (xfrm_id_proto_match(x->id.proto, proto)) |
768 | count++; | 1095 | count++; |
769 | } | 1096 | } |
770 | } | 1097 | } |
@@ -773,9 +1100,9 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | |||
773 | goto out; | 1100 | goto out; |
774 | } | 1101 | } |
775 | 1102 | ||
776 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 1103 | for (i = 0; i <= xfrm_state_hmask; i++) { |
777 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 1104 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { |
778 | if (proto != IPSEC_PROTO_ANY && x->id.proto != proto) | 1105 | if (!xfrm_id_proto_match(x->id.proto, proto)) |
779 | continue; | 1106 | continue; |
780 | err = func(x, --count, data); | 1107 | err = func(x, --count, data); |
781 | if (err) | 1108 | if (err) |
@@ -832,10 +1159,8 @@ void xfrm_replay_notify(struct xfrm_state *x, int event) | |||
832 | km_state_notify(x, &c); | 1159 | km_state_notify(x, &c); |
833 | 1160 | ||
834 | if (x->replay_maxage && | 1161 | if (x->replay_maxage && |
835 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) { | 1162 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) |
836 | xfrm_state_hold(x); | ||
837 | x->xflags &= ~XFRM_TIME_DEFER; | 1163 | x->xflags &= ~XFRM_TIME_DEFER; |
838 | } | ||
839 | } | 1164 | } |
840 | EXPORT_SYMBOL(xfrm_replay_notify); | 1165 | EXPORT_SYMBOL(xfrm_replay_notify); |
841 | 1166 | ||
@@ -853,7 +1178,6 @@ static void xfrm_replay_timer_handler(unsigned long data) | |||
853 | } | 1178 | } |
854 | 1179 | ||
855 | spin_unlock(&x->lock); | 1180 | spin_unlock(&x->lock); |
856 | xfrm_state_put(x); | ||
857 | } | 1181 | } |
858 | 1182 | ||
859 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) | 1183 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) |
@@ -997,6 +1321,25 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) | |||
997 | } | 1321 | } |
998 | EXPORT_SYMBOL(km_policy_expired); | 1322 | EXPORT_SYMBOL(km_policy_expired); |
999 | 1323 | ||
1324 | int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) | ||
1325 | { | ||
1326 | int err = -EINVAL; | ||
1327 | int ret; | ||
1328 | struct xfrm_mgr *km; | ||
1329 | |||
1330 | read_lock(&xfrm_km_lock); | ||
1331 | list_for_each_entry(km, &xfrm_km_list, list) { | ||
1332 | if (km->report) { | ||
1333 | ret = km->report(proto, sel, addr); | ||
1334 | if (!ret) | ||
1335 | err = ret; | ||
1336 | } | ||
1337 | } | ||
1338 | read_unlock(&xfrm_km_lock); | ||
1339 | return err; | ||
1340 | } | ||
1341 | EXPORT_SYMBOL(km_report); | ||
1342 | |||
1000 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 1343 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
1001 | { | 1344 | { |
1002 | int err; | 1345 | int err; |
@@ -1018,7 +1361,7 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen | |||
1018 | err = -EINVAL; | 1361 | err = -EINVAL; |
1019 | read_lock(&xfrm_km_lock); | 1362 | read_lock(&xfrm_km_lock); |
1020 | list_for_each_entry(km, &xfrm_km_list, list) { | 1363 | list_for_each_entry(km, &xfrm_km_list, list) { |
1021 | pol = km->compile_policy(sk->sk_family, optname, data, | 1364 | pol = km->compile_policy(sk, optname, data, |
1022 | optlen, &err); | 1365 | optlen, &err); |
1023 | if (err >= 0) | 1366 | if (err >= 0) |
1024 | break; | 1367 | break; |
@@ -1065,11 +1408,8 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1065 | write_lock_bh(&xfrm_state_afinfo_lock); | 1408 | write_lock_bh(&xfrm_state_afinfo_lock); |
1066 | if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) | 1409 | if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) |
1067 | err = -ENOBUFS; | 1410 | err = -ENOBUFS; |
1068 | else { | 1411 | else |
1069 | afinfo->state_bydst = xfrm_state_bydst; | ||
1070 | afinfo->state_byspi = xfrm_state_byspi; | ||
1071 | xfrm_state_afinfo[afinfo->family] = afinfo; | 1412 | xfrm_state_afinfo[afinfo->family] = afinfo; |
1072 | } | ||
1073 | write_unlock_bh(&xfrm_state_afinfo_lock); | 1413 | write_unlock_bh(&xfrm_state_afinfo_lock); |
1074 | return err; | 1414 | return err; |
1075 | } | 1415 | } |
@@ -1086,11 +1426,8 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1086 | if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { | 1426 | if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { |
1087 | if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) | 1427 | if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) |
1088 | err = -EINVAL; | 1428 | err = -EINVAL; |
1089 | else { | 1429 | else |
1090 | xfrm_state_afinfo[afinfo->family] = NULL; | 1430 | xfrm_state_afinfo[afinfo->family] = NULL; |
1091 | afinfo->state_byspi = NULL; | ||
1092 | afinfo->state_bydst = NULL; | ||
1093 | } | ||
1094 | } | 1431 | } |
1095 | write_unlock_bh(&xfrm_state_afinfo_lock); | 1432 | write_unlock_bh(&xfrm_state_afinfo_lock); |
1096 | return err; | 1433 | return err; |
@@ -1206,12 +1543,17 @@ EXPORT_SYMBOL(xfrm_init_state); | |||
1206 | 1543 | ||
1207 | void __init xfrm_state_init(void) | 1544 | void __init xfrm_state_init(void) |
1208 | { | 1545 | { |
1209 | int i; | 1546 | unsigned int sz; |
1547 | |||
1548 | sz = sizeof(struct hlist_head) * 8; | ||
1549 | |||
1550 | xfrm_state_bydst = xfrm_hash_alloc(sz); | ||
1551 | xfrm_state_bysrc = xfrm_hash_alloc(sz); | ||
1552 | xfrm_state_byspi = xfrm_hash_alloc(sz); | ||
1553 | if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) | ||
1554 | panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); | ||
1555 | xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); | ||
1210 | 1556 | ||
1211 | for (i=0; i<XFRM_DST_HSIZE; i++) { | ||
1212 | INIT_LIST_HEAD(&xfrm_state_bydst[i]); | ||
1213 | INIT_LIST_HEAD(&xfrm_state_byspi[i]); | ||
1214 | } | ||
1215 | INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); | 1557 | INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); |
1216 | } | 1558 | } |
1217 | 1559 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 3e6a722d072e..c59a78d2923a 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/crypto.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/types.h> | 16 | #include <linux/types.h> |
@@ -27,6 +28,9 @@ | |||
27 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
28 | #include <net/netlink.h> | 29 | #include <net/netlink.h> |
29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
32 | #include <linux/in6.h> | ||
33 | #endif | ||
30 | 34 | ||
31 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 35 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
32 | { | 36 | { |
@@ -86,6 +90,22 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
86 | return 0; | 90 | return 0; |
87 | } | 91 | } |
88 | 92 | ||
93 | static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, | ||
94 | xfrm_address_t **addrp) | ||
95 | { | ||
96 | struct rtattr *rt = xfrma[type - 1]; | ||
97 | |||
98 | if (!rt) | ||
99 | return 0; | ||
100 | |||
101 | if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) | ||
102 | return -EINVAL; | ||
103 | |||
104 | if (addrp) | ||
105 | *addrp = RTA_DATA(rt); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
89 | 109 | ||
90 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | 110 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) |
91 | { | 111 | { |
@@ -156,6 +176,19 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
156 | goto out; | 176 | goto out; |
157 | break; | 177 | break; |
158 | 178 | ||
179 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
180 | case IPPROTO_DSTOPTS: | ||
181 | case IPPROTO_ROUTING: | ||
182 | if (xfrma[XFRMA_ALG_COMP-1] || | ||
183 | xfrma[XFRMA_ALG_AUTH-1] || | ||
184 | xfrma[XFRMA_ALG_CRYPT-1] || | ||
185 | xfrma[XFRMA_ENCAP-1] || | ||
186 | xfrma[XFRMA_SEC_CTX-1] || | ||
187 | !xfrma[XFRMA_COADDR-1]) | ||
188 | goto out; | ||
189 | break; | ||
190 | #endif | ||
191 | |||
159 | default: | 192 | default: |
160 | goto out; | 193 | goto out; |
161 | }; | 194 | }; |
@@ -170,11 +203,14 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
170 | goto out; | 203 | goto out; |
171 | if ((err = verify_sec_ctx_len(xfrma))) | 204 | if ((err = verify_sec_ctx_len(xfrma))) |
172 | goto out; | 205 | goto out; |
206 | if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) | ||
207 | goto out; | ||
173 | 208 | ||
174 | err = -EINVAL; | 209 | err = -EINVAL; |
175 | switch (p->mode) { | 210 | switch (p->mode) { |
176 | case 0: | 211 | case XFRM_MODE_TRANSPORT: |
177 | case 1: | 212 | case XFRM_MODE_TUNNEL: |
213 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
178 | break; | 214 | break; |
179 | 215 | ||
180 | default: | 216 | default: |
@@ -212,6 +248,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | |||
212 | return -ENOMEM; | 248 | return -ENOMEM; |
213 | 249 | ||
214 | memcpy(p, ualg, len); | 250 | memcpy(p, ualg, len); |
251 | strcpy(p->alg_name, algo->name); | ||
215 | *algpp = p; | 252 | *algpp = p; |
216 | return 0; | 253 | return 0; |
217 | } | 254 | } |
@@ -258,6 +295,24 @@ static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | |||
258 | return security_xfrm_state_alloc(x, uctx); | 295 | return security_xfrm_state_alloc(x, uctx); |
259 | } | 296 | } |
260 | 297 | ||
298 | static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) | ||
299 | { | ||
300 | struct rtattr *rta = u_arg; | ||
301 | xfrm_address_t *p, *uaddrp; | ||
302 | |||
303 | if (!rta) | ||
304 | return 0; | ||
305 | |||
306 | uaddrp = RTA_DATA(rta); | ||
307 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
308 | if (!p) | ||
309 | return -ENOMEM; | ||
310 | |||
311 | memcpy(p, uaddrp, sizeof(*p)); | ||
312 | *addrpp = p; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
261 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 316 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
262 | { | 317 | { |
263 | memcpy(&x->id, &p->id, sizeof(x->id)); | 318 | memcpy(&x->id, &p->id, sizeof(x->id)); |
@@ -347,7 +402,8 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
347 | goto error; | 402 | goto error; |
348 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) | 403 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) |
349 | goto error; | 404 | goto error; |
350 | 405 | if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) | |
406 | goto error; | ||
351 | err = xfrm_init_state(x); | 407 | err = xfrm_init_state(x); |
352 | if (err) | 408 | if (err) |
353 | goto error; | 409 | goto error; |
@@ -416,16 +472,48 @@ out: | |||
416 | return err; | 472 | return err; |
417 | } | 473 | } |
418 | 474 | ||
475 | static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, | ||
476 | struct rtattr **xfrma, | ||
477 | int *errp) | ||
478 | { | ||
479 | struct xfrm_state *x = NULL; | ||
480 | int err; | ||
481 | |||
482 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | ||
483 | err = -ESRCH; | ||
484 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | ||
485 | } else { | ||
486 | xfrm_address_t *saddr = NULL; | ||
487 | |||
488 | err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); | ||
489 | if (err) | ||
490 | goto out; | ||
491 | |||
492 | if (!saddr) { | ||
493 | err = -EINVAL; | ||
494 | goto out; | ||
495 | } | ||
496 | |||
497 | x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, | ||
498 | p->family); | ||
499 | } | ||
500 | |||
501 | out: | ||
502 | if (!x && errp) | ||
503 | *errp = err; | ||
504 | return x; | ||
505 | } | ||
506 | |||
419 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 507 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
420 | { | 508 | { |
421 | struct xfrm_state *x; | 509 | struct xfrm_state *x; |
422 | int err; | 510 | int err = -ESRCH; |
423 | struct km_event c; | 511 | struct km_event c; |
424 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 512 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
425 | 513 | ||
426 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 514 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
427 | if (x == NULL) | 515 | if (x == NULL) |
428 | return -ESRCH; | 516 | return err; |
429 | 517 | ||
430 | if ((err = security_xfrm_state_delete(x)) != 0) | 518 | if ((err = security_xfrm_state_delete(x)) != 0) |
431 | goto out; | 519 | goto out; |
@@ -519,6 +607,13 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
519 | uctx->ctx_len = x->security->ctx_len; | 607 | uctx->ctx_len = x->security->ctx_len; |
520 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | 608 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); |
521 | } | 609 | } |
610 | |||
611 | if (x->coaddr) | ||
612 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); | ||
613 | |||
614 | if (x->lastused) | ||
615 | RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); | ||
616 | |||
522 | nlh->nlmsg_len = skb->tail - b; | 617 | nlh->nlmsg_len = skb->tail - b; |
523 | out: | 618 | out: |
524 | sp->this_idx++; | 619 | sp->this_idx++; |
@@ -540,7 +635,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | |||
540 | info.nlmsg_flags = NLM_F_MULTI; | 635 | info.nlmsg_flags = NLM_F_MULTI; |
541 | info.this_idx = 0; | 636 | info.this_idx = 0; |
542 | info.start_idx = cb->args[0]; | 637 | info.start_idx = cb->args[0]; |
543 | (void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info); | 638 | (void) xfrm_state_walk(0, dump_one_state, &info); |
544 | cb->args[0] = info.this_idx; | 639 | cb->args[0] = info.this_idx; |
545 | 640 | ||
546 | return skb->len; | 641 | return skb->len; |
@@ -576,10 +671,9 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
576 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 671 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
577 | struct xfrm_state *x; | 672 | struct xfrm_state *x; |
578 | struct sk_buff *resp_skb; | 673 | struct sk_buff *resp_skb; |
579 | int err; | 674 | int err = -ESRCH; |
580 | 675 | ||
581 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 676 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
582 | err = -ESRCH; | ||
583 | if (x == NULL) | 677 | if (x == NULL) |
584 | goto out_noput; | 678 | goto out_noput; |
585 | 679 | ||
@@ -692,6 +786,22 @@ static int verify_policy_dir(__u8 dir) | |||
692 | return 0; | 786 | return 0; |
693 | } | 787 | } |
694 | 788 | ||
789 | static int verify_policy_type(__u8 type) | ||
790 | { | ||
791 | switch (type) { | ||
792 | case XFRM_POLICY_TYPE_MAIN: | ||
793 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
794 | case XFRM_POLICY_TYPE_SUB: | ||
795 | #endif | ||
796 | break; | ||
797 | |||
798 | default: | ||
799 | return -EINVAL; | ||
800 | }; | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | |||
695 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 805 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
696 | { | 806 | { |
697 | switch (p->share) { | 807 | switch (p->share) { |
@@ -785,6 +895,29 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | |||
785 | return 0; | 895 | return 0; |
786 | } | 896 | } |
787 | 897 | ||
898 | static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) | ||
899 | { | ||
900 | struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; | ||
901 | struct xfrm_userpolicy_type *upt; | ||
902 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
903 | int err; | ||
904 | |||
905 | if (rt) { | ||
906 | if (rt->rta_len < sizeof(*upt)) | ||
907 | return -EINVAL; | ||
908 | |||
909 | upt = RTA_DATA(rt); | ||
910 | type = upt->type; | ||
911 | } | ||
912 | |||
913 | err = verify_policy_type(type); | ||
914 | if (err) | ||
915 | return err; | ||
916 | |||
917 | *tp = type; | ||
918 | return 0; | ||
919 | } | ||
920 | |||
788 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) | 921 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) |
789 | { | 922 | { |
790 | xp->priority = p->priority; | 923 | xp->priority = p->priority; |
@@ -823,16 +956,20 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
823 | 956 | ||
824 | copy_from_user_policy(xp, p); | 957 | copy_from_user_policy(xp, p); |
825 | 958 | ||
959 | err = copy_from_user_policy_type(&xp->type, xfrma); | ||
960 | if (err) | ||
961 | goto error; | ||
962 | |||
826 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | 963 | if (!(err = copy_from_user_tmpl(xp, xfrma))) |
827 | err = copy_from_user_sec_ctx(xp, xfrma); | 964 | err = copy_from_user_sec_ctx(xp, xfrma); |
828 | 965 | if (err) | |
829 | if (err) { | 966 | goto error; |
830 | *errp = err; | ||
831 | kfree(xp); | ||
832 | xp = NULL; | ||
833 | } | ||
834 | 967 | ||
835 | return xp; | 968 | return xp; |
969 | error: | ||
970 | *errp = err; | ||
971 | kfree(xp); | ||
972 | return NULL; | ||
836 | } | 973 | } |
837 | 974 | ||
838 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 975 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
@@ -909,27 +1046,63 @@ rtattr_failure: | |||
909 | return -1; | 1046 | return -1; |
910 | } | 1047 | } |
911 | 1048 | ||
912 | static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | 1049 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) |
913 | { | 1050 | { |
914 | if (xp->security) { | 1051 | int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; |
915 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | 1052 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); |
916 | xp->security->ctx_len; | 1053 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
917 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | 1054 | |
918 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 1055 | uctx->exttype = XFRMA_SEC_CTX; |
1056 | uctx->len = ctx_size; | ||
1057 | uctx->ctx_doi = s->ctx_doi; | ||
1058 | uctx->ctx_alg = s->ctx_alg; | ||
1059 | uctx->ctx_len = s->ctx_len; | ||
1060 | memcpy(uctx + 1, s->ctx_str, s->ctx_len); | ||
1061 | return 0; | ||
919 | 1062 | ||
920 | uctx->exttype = XFRMA_SEC_CTX; | 1063 | rtattr_failure: |
921 | uctx->len = ctx_size; | 1064 | return -1; |
922 | uctx->ctx_doi = xp->security->ctx_doi; | 1065 | } |
923 | uctx->ctx_alg = xp->security->ctx_alg; | 1066 | |
924 | uctx->ctx_len = xp->security->ctx_len; | 1067 | static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) |
925 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | 1068 | { |
1069 | if (x->security) { | ||
1070 | return copy_sec_ctx(x->security, skb); | ||
926 | } | 1071 | } |
927 | return 0; | 1072 | return 0; |
1073 | } | ||
928 | 1074 | ||
929 | rtattr_failure: | 1075 | static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) |
1076 | { | ||
1077 | if (xp->security) { | ||
1078 | return copy_sec_ctx(xp->security, skb); | ||
1079 | } | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1084 | static int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) | ||
1085 | { | ||
1086 | struct xfrm_userpolicy_type upt; | ||
1087 | |||
1088 | memset(&upt, 0, sizeof(upt)); | ||
1089 | upt.type = xp->type; | ||
1090 | |||
1091 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | ||
1092 | |||
1093 | return 0; | ||
1094 | |||
1095 | rtattr_failure: | ||
930 | return -1; | 1096 | return -1; |
931 | } | 1097 | } |
932 | 1098 | ||
1099 | #else | ||
1100 | static inline int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) | ||
1101 | { | ||
1102 | return 0; | ||
1103 | } | ||
1104 | #endif | ||
1105 | |||
933 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 1106 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
934 | { | 1107 | { |
935 | struct xfrm_dump_info *sp = ptr; | 1108 | struct xfrm_dump_info *sp = ptr; |
@@ -953,6 +1126,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
953 | goto nlmsg_failure; | 1126 | goto nlmsg_failure; |
954 | if (copy_to_user_sec_ctx(xp, skb)) | 1127 | if (copy_to_user_sec_ctx(xp, skb)) |
955 | goto nlmsg_failure; | 1128 | goto nlmsg_failure; |
1129 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1130 | goto nlmsg_failure; | ||
956 | 1131 | ||
957 | nlh->nlmsg_len = skb->tail - b; | 1132 | nlh->nlmsg_len = skb->tail - b; |
958 | out: | 1133 | out: |
@@ -974,7 +1149,10 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | |||
974 | info.nlmsg_flags = NLM_F_MULTI; | 1149 | info.nlmsg_flags = NLM_F_MULTI; |
975 | info.this_idx = 0; | 1150 | info.this_idx = 0; |
976 | info.start_idx = cb->args[0]; | 1151 | info.start_idx = cb->args[0]; |
977 | (void) xfrm_policy_walk(dump_one_policy, &info); | 1152 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); |
1153 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1154 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); | ||
1155 | #endif | ||
978 | cb->args[0] = info.this_idx; | 1156 | cb->args[0] = info.this_idx; |
979 | 1157 | ||
980 | return skb->len; | 1158 | return skb->len; |
@@ -1010,6 +1188,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1010 | { | 1188 | { |
1011 | struct xfrm_policy *xp; | 1189 | struct xfrm_policy *xp; |
1012 | struct xfrm_userpolicy_id *p; | 1190 | struct xfrm_userpolicy_id *p; |
1191 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1013 | int err; | 1192 | int err; |
1014 | struct km_event c; | 1193 | struct km_event c; |
1015 | int delete; | 1194 | int delete; |
@@ -1017,12 +1196,16 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1017 | p = NLMSG_DATA(nlh); | 1196 | p = NLMSG_DATA(nlh); |
1018 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1197 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
1019 | 1198 | ||
1199 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1200 | if (err) | ||
1201 | return err; | ||
1202 | |||
1020 | err = verify_policy_dir(p->dir); | 1203 | err = verify_policy_dir(p->dir); |
1021 | if (err) | 1204 | if (err) |
1022 | return err; | 1205 | return err; |
1023 | 1206 | ||
1024 | if (p->index) | 1207 | if (p->index) |
1025 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 1208 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); |
1026 | else { | 1209 | else { |
1027 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1210 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1028 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1211 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1039,7 +1222,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1039 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1222 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1040 | return err; | 1223 | return err; |
1041 | } | 1224 | } |
1042 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete); | 1225 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); |
1043 | security_xfrm_policy_free(&tmp); | 1226 | security_xfrm_policy_free(&tmp); |
1044 | } | 1227 | } |
1045 | if (xp == NULL) | 1228 | if (xp == NULL) |
@@ -1222,9 +1405,16 @@ out: | |||
1222 | 1405 | ||
1223 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1406 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1224 | { | 1407 | { |
1225 | struct km_event c; | 1408 | struct km_event c; |
1409 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1410 | int err; | ||
1411 | |||
1412 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1413 | if (err) | ||
1414 | return err; | ||
1226 | 1415 | ||
1227 | xfrm_policy_flush(); | 1416 | xfrm_policy_flush(type); |
1417 | c.data.type = type; | ||
1228 | c.event = nlh->nlmsg_type; | 1418 | c.event = nlh->nlmsg_type; |
1229 | c.seq = nlh->nlmsg_seq; | 1419 | c.seq = nlh->nlmsg_seq; |
1230 | c.pid = nlh->nlmsg_pid; | 1420 | c.pid = nlh->nlmsg_pid; |
@@ -1237,10 +1427,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1237 | struct xfrm_policy *xp; | 1427 | struct xfrm_policy *xp; |
1238 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | 1428 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); |
1239 | struct xfrm_userpolicy_info *p = &up->pol; | 1429 | struct xfrm_userpolicy_info *p = &up->pol; |
1430 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1240 | int err = -ENOENT; | 1431 | int err = -ENOENT; |
1241 | 1432 | ||
1433 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1434 | if (err) | ||
1435 | return err; | ||
1436 | |||
1242 | if (p->index) | 1437 | if (p->index) |
1243 | xp = xfrm_policy_byid(p->dir, p->index, 0); | 1438 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); |
1244 | else { | 1439 | else { |
1245 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1440 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1246 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1441 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1257,7 +1452,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1257 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1452 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1258 | return err; | 1453 | return err; |
1259 | } | 1454 | } |
1260 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); | 1455 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0); |
1261 | security_xfrm_policy_free(&tmp); | 1456 | security_xfrm_policy_free(&tmp); |
1262 | } | 1457 | } |
1263 | 1458 | ||
@@ -1384,6 +1579,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1384 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1579 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1385 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1580 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1386 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1581 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1582 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), | ||
1387 | }; | 1583 | }; |
1388 | 1584 | ||
1389 | #undef XMSGSIZE | 1585 | #undef XMSGSIZE |
@@ -1708,7 +1904,9 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
1708 | 1904 | ||
1709 | if (copy_to_user_tmpl(xp, skb) < 0) | 1905 | if (copy_to_user_tmpl(xp, skb) < 0) |
1710 | goto nlmsg_failure; | 1906 | goto nlmsg_failure; |
1711 | if (copy_to_user_sec_ctx(xp, skb)) | 1907 | if (copy_to_user_state_sec_ctx(x, skb)) |
1908 | goto nlmsg_failure; | ||
1909 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1712 | goto nlmsg_failure; | 1910 | goto nlmsg_failure; |
1713 | 1911 | ||
1714 | nlh->nlmsg_len = skb->tail - b; | 1912 | nlh->nlmsg_len = skb->tail - b; |
@@ -1742,7 +1940,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
1742 | /* User gives us xfrm_user_policy_info followed by an array of 0 | 1940 | /* User gives us xfrm_user_policy_info followed by an array of 0 |
1743 | * or more templates. | 1941 | * or more templates. |
1744 | */ | 1942 | */ |
1745 | static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | 1943 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, |
1746 | u8 *data, int len, int *dir) | 1944 | u8 *data, int len, int *dir) |
1747 | { | 1945 | { |
1748 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; | 1946 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; |
@@ -1750,7 +1948,7 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1750 | struct xfrm_policy *xp; | 1948 | struct xfrm_policy *xp; |
1751 | int nr; | 1949 | int nr; |
1752 | 1950 | ||
1753 | switch (family) { | 1951 | switch (sk->sk_family) { |
1754 | case AF_INET: | 1952 | case AF_INET: |
1755 | if (opt != IP_XFRM_POLICY) { | 1953 | if (opt != IP_XFRM_POLICY) { |
1756 | *dir = -EOPNOTSUPP; | 1954 | *dir = -EOPNOTSUPP; |
@@ -1790,8 +1988,18 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1790 | } | 1988 | } |
1791 | 1989 | ||
1792 | copy_from_user_policy(xp, p); | 1990 | copy_from_user_policy(xp, p); |
1991 | xp->type = XFRM_POLICY_TYPE_MAIN; | ||
1793 | copy_templates(xp, ut, nr); | 1992 | copy_templates(xp, ut, nr); |
1794 | 1993 | ||
1994 | if (!xp->security) { | ||
1995 | int err = security_xfrm_sock_policy_alloc(xp, sk); | ||
1996 | if (err) { | ||
1997 | kfree(xp); | ||
1998 | *dir = err; | ||
1999 | return NULL; | ||
2000 | } | ||
2001 | } | ||
2002 | |||
1795 | *dir = p->dir; | 2003 | *dir = p->dir; |
1796 | 2004 | ||
1797 | return xp; | 2005 | return xp; |
@@ -1814,6 +2022,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
1814 | goto nlmsg_failure; | 2022 | goto nlmsg_failure; |
1815 | if (copy_to_user_sec_ctx(xp, skb)) | 2023 | if (copy_to_user_sec_ctx(xp, skb)) |
1816 | goto nlmsg_failure; | 2024 | goto nlmsg_failure; |
2025 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2026 | goto nlmsg_failure; | ||
1817 | upe->hard = !!hard; | 2027 | upe->hard = !!hard; |
1818 | 2028 | ||
1819 | nlh->nlmsg_len = skb->tail - b; | 2029 | nlh->nlmsg_len = skb->tail - b; |
@@ -1885,6 +2095,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
1885 | copy_to_user_policy(xp, p, dir); | 2095 | copy_to_user_policy(xp, p, dir); |
1886 | if (copy_to_user_tmpl(xp, skb) < 0) | 2096 | if (copy_to_user_tmpl(xp, skb) < 0) |
1887 | goto nlmsg_failure; | 2097 | goto nlmsg_failure; |
2098 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2099 | goto nlmsg_failure; | ||
1888 | 2100 | ||
1889 | nlh->nlmsg_len = skb->tail - b; | 2101 | nlh->nlmsg_len = skb->tail - b; |
1890 | 2102 | ||
@@ -1902,6 +2114,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1902 | struct nlmsghdr *nlh; | 2114 | struct nlmsghdr *nlh; |
1903 | struct sk_buff *skb; | 2115 | struct sk_buff *skb; |
1904 | unsigned char *b; | 2116 | unsigned char *b; |
2117 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2118 | struct xfrm_userpolicy_type upt; | ||
2119 | #endif | ||
1905 | int len = NLMSG_LENGTH(0); | 2120 | int len = NLMSG_LENGTH(0); |
1906 | 2121 | ||
1907 | skb = alloc_skb(len, GFP_ATOMIC); | 2122 | skb = alloc_skb(len, GFP_ATOMIC); |
@@ -1911,6 +2126,13 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1911 | 2126 | ||
1912 | 2127 | ||
1913 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); | 2128 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); |
2129 | nlh->nlmsg_flags = 0; | ||
2130 | |||
2131 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2132 | memset(&upt, 0, sizeof(upt)); | ||
2133 | upt.type = c->data.type; | ||
2134 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | ||
2135 | #endif | ||
1914 | 2136 | ||
1915 | nlh->nlmsg_len = skb->tail - b; | 2137 | nlh->nlmsg_len = skb->tail - b; |
1916 | 2138 | ||
@@ -1918,6 +2140,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1918 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2140 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
1919 | 2141 | ||
1920 | nlmsg_failure: | 2142 | nlmsg_failure: |
2143 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2144 | rtattr_failure: | ||
2145 | #endif | ||
1921 | kfree_skb(skb); | 2146 | kfree_skb(skb); |
1922 | return -1; | 2147 | return -1; |
1923 | } | 2148 | } |
@@ -1942,19 +2167,64 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_ev | |||
1942 | 2167 | ||
1943 | } | 2168 | } |
1944 | 2169 | ||
2170 | static int build_report(struct sk_buff *skb, u8 proto, | ||
2171 | struct xfrm_selector *sel, xfrm_address_t *addr) | ||
2172 | { | ||
2173 | struct xfrm_user_report *ur; | ||
2174 | struct nlmsghdr *nlh; | ||
2175 | unsigned char *b = skb->tail; | ||
2176 | |||
2177 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); | ||
2178 | ur = NLMSG_DATA(nlh); | ||
2179 | nlh->nlmsg_flags = 0; | ||
2180 | |||
2181 | ur->proto = proto; | ||
2182 | memcpy(&ur->sel, sel, sizeof(ur->sel)); | ||
2183 | |||
2184 | if (addr) | ||
2185 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); | ||
2186 | |||
2187 | nlh->nlmsg_len = skb->tail - b; | ||
2188 | return skb->len; | ||
2189 | |||
2190 | nlmsg_failure: | ||
2191 | rtattr_failure: | ||
2192 | skb_trim(skb, b - skb->data); | ||
2193 | return -1; | ||
2194 | } | ||
2195 | |||
2196 | static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, | ||
2197 | xfrm_address_t *addr) | ||
2198 | { | ||
2199 | struct sk_buff *skb; | ||
2200 | size_t len; | ||
2201 | |||
2202 | len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); | ||
2203 | skb = alloc_skb(len, GFP_ATOMIC); | ||
2204 | if (skb == NULL) | ||
2205 | return -ENOMEM; | ||
2206 | |||
2207 | if (build_report(skb, proto, sel, addr) < 0) | ||
2208 | BUG(); | ||
2209 | |||
2210 | NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; | ||
2211 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); | ||
2212 | } | ||
2213 | |||
1945 | static struct xfrm_mgr netlink_mgr = { | 2214 | static struct xfrm_mgr netlink_mgr = { |
1946 | .id = "netlink", | 2215 | .id = "netlink", |
1947 | .notify = xfrm_send_state_notify, | 2216 | .notify = xfrm_send_state_notify, |
1948 | .acquire = xfrm_send_acquire, | 2217 | .acquire = xfrm_send_acquire, |
1949 | .compile_policy = xfrm_compile_policy, | 2218 | .compile_policy = xfrm_compile_policy, |
1950 | .notify_policy = xfrm_send_policy_notify, | 2219 | .notify_policy = xfrm_send_policy_notify, |
2220 | .report = xfrm_send_report, | ||
1951 | }; | 2221 | }; |
1952 | 2222 | ||
1953 | static int __init xfrm_user_init(void) | 2223 | static int __init xfrm_user_init(void) |
1954 | { | 2224 | { |
1955 | struct sock *nlsk; | 2225 | struct sock *nlsk; |
1956 | 2226 | ||
1957 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 2227 | printk(KERN_INFO "Initializing XFRM netlink socket\n"); |
1958 | 2228 | ||
1959 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 2229 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
1960 | xfrm_netlink_rcv, THIS_MODULE); | 2230 | xfrm_netlink_rcv, THIS_MODULE); |