diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 640 |
1 files changed, 491 insertions, 149 deletions
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 | ||