blob: cd1d5e11ee748649f81a4793fcf198562a03a22b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * xfrm_state.c
3 *
4 * Changes:
5 * Mitsuru KANDA @USAGI
6 * Kazunori MIYAZAWA @USAGI
7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
8 * IPv6 support
9 * YOSHIFUJI Hideaki @USAGI
10 * Split up af-specific functions
11 * Derek Atkins <derek@ihtfp.com>
12 * Add UDP Encapsulation
Trent Jaegerdf718372005-12-13 23:12:27 -080013 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 */
15
16#include <linux/workqueue.h>
17#include <net/xfrm.h>
18#include <linux/pfkeyv2.h>
19#include <linux/ipsec.h>
20#include <linux/module.h>
21#include <asm/uaccess.h>
22
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -080023u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME;
24u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025/* Each xfrm_state may be linked to two tables:
26
27 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
28 2. Hash table by daddr to find what SAs exist for given
29 destination/tunnel endpoint. (output)
30 */
31
32static DEFINE_SPINLOCK(xfrm_state_lock);
33
34/* Hash table to find appropriate SA towards given target (endpoint
35 * of tunnel or destination of transport mode) allowed by selector.
36 *
37 * Main use is finding SA after policy selected tunnel or transport mode.
38 * Also, it can be used by ah/esp icmp error handler to find offending SA.
39 */
40static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
41static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
42
43DECLARE_WAIT_QUEUE_HEAD(km_waitq);
44EXPORT_SYMBOL(km_waitq);
45
46static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
47static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
48
49static struct work_struct xfrm_state_gc_work;
50static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
51static DEFINE_SPINLOCK(xfrm_state_gc_lock);
52
53static int xfrm_state_gc_flush_bundles;
54
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -080055int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
58static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
59
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -080060int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -080061void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63static void xfrm_state_gc_destroy(struct xfrm_state *x)
64{
65 if (del_timer(&x->timer))
66 BUG();
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -080067 if (del_timer(&x->rtimer))
68 BUG();
Jesper Juhla51482b2005-11-08 09:41:34 -080069 kfree(x->aalg);
70 kfree(x->ealg);
71 kfree(x->calg);
72 kfree(x->encap);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 if (x->type) {
74 x->type->destructor(x);
75 xfrm_put_type(x->type);
76 }
Trent Jaegerdf718372005-12-13 23:12:27 -080077 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 kfree(x);
79}
80
81static void xfrm_state_gc_task(void *data)
82{
83 struct xfrm_state *x;
84 struct list_head *entry, *tmp;
85 struct list_head gc_list = LIST_HEAD_INIT(gc_list);
86
87 if (xfrm_state_gc_flush_bundles) {
88 xfrm_state_gc_flush_bundles = 0;
89 xfrm_flush_bundles();
90 }
91
92 spin_lock_bh(&xfrm_state_gc_lock);
93 list_splice_init(&xfrm_state_gc_list, &gc_list);
94 spin_unlock_bh(&xfrm_state_gc_lock);
95
96 list_for_each_safe(entry, tmp, &gc_list) {
97 x = list_entry(entry, struct xfrm_state, bydst);
98 xfrm_state_gc_destroy(x);
99 }
100 wake_up(&km_waitq);
101}
102
103static inline unsigned long make_jiffies(long secs)
104{
105 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
106 return MAX_SCHEDULE_TIMEOUT-1;
107 else
108 return secs*HZ;
109}
110
111static void xfrm_timer_handler(unsigned long data)
112{
113 struct xfrm_state *x = (struct xfrm_state*)data;
114 unsigned long now = (unsigned long)xtime.tv_sec;
115 long next = LONG_MAX;
116 int warn = 0;
117
118 spin_lock(&x->lock);
119 if (x->km.state == XFRM_STATE_DEAD)
120 goto out;
121 if (x->km.state == XFRM_STATE_EXPIRED)
122 goto expired;
123 if (x->lft.hard_add_expires_seconds) {
124 long tmo = x->lft.hard_add_expires_seconds +
125 x->curlft.add_time - now;
126 if (tmo <= 0)
127 goto expired;
128 if (tmo < next)
129 next = tmo;
130 }
131 if (x->lft.hard_use_expires_seconds) {
132 long tmo = x->lft.hard_use_expires_seconds +
133 (x->curlft.use_time ? : now) - now;
134 if (tmo <= 0)
135 goto expired;
136 if (tmo < next)
137 next = tmo;
138 }
139 if (x->km.dying)
140 goto resched;
141 if (x->lft.soft_add_expires_seconds) {
142 long tmo = x->lft.soft_add_expires_seconds +
143 x->curlft.add_time - now;
144 if (tmo <= 0)
145 warn = 1;
146 else if (tmo < next)
147 next = tmo;
148 }
149 if (x->lft.soft_use_expires_seconds) {
150 long tmo = x->lft.soft_use_expires_seconds +
151 (x->curlft.use_time ? : now) - now;
152 if (tmo <= 0)
153 warn = 1;
154 else if (tmo < next)
155 next = tmo;
156 }
157
Herbert Xu4666faa2005-06-18 22:43:22 -0700158 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800160 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161resched:
162 if (next != LONG_MAX &&
163 !mod_timer(&x->timer, jiffies + make_jiffies(next)))
164 xfrm_state_hold(x);
165 goto out;
166
167expired:
168 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
169 x->km.state = XFRM_STATE_EXPIRED;
170 wake_up(&km_waitq);
171 next = 2;
172 goto resched;
173 }
Herbert Xu4666faa2005-06-18 22:43:22 -0700174 if (!__xfrm_state_delete(x) && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800175 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177out:
178 spin_unlock(&x->lock);
179 xfrm_state_put(x);
180}
181
David S. Miller0ac84752006-03-20 19:18:23 -0800182static void xfrm_replay_timer_handler(unsigned long data);
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184struct xfrm_state *xfrm_state_alloc(void)
185{
186 struct xfrm_state *x;
187
188 x = kmalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
189
190 if (x) {
191 memset(x, 0, sizeof(struct xfrm_state));
192 atomic_set(&x->refcnt, 1);
193 atomic_set(&x->tunnel_users, 0);
194 INIT_LIST_HEAD(&x->bydst);
195 INIT_LIST_HEAD(&x->byspi);
196 init_timer(&x->timer);
197 x->timer.function = xfrm_timer_handler;
198 x->timer.data = (unsigned long)x;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800199 init_timer(&x->rtimer);
200 x->rtimer.function = xfrm_replay_timer_handler;
201 x->rtimer.data = (unsigned long)x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 x->curlft.add_time = (unsigned long)xtime.tv_sec;
203 x->lft.soft_byte_limit = XFRM_INF;
204 x->lft.soft_packet_limit = XFRM_INF;
205 x->lft.hard_byte_limit = XFRM_INF;
206 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800207 x->replay_maxage = 0;
208 x->replay_maxdiff = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 spin_lock_init(&x->lock);
210 }
211 return x;
212}
213EXPORT_SYMBOL(xfrm_state_alloc);
214
215void __xfrm_state_destroy(struct xfrm_state *x)
216{
217 BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
218
219 spin_lock_bh(&xfrm_state_gc_lock);
220 list_add(&x->bydst, &xfrm_state_gc_list);
221 spin_unlock_bh(&xfrm_state_gc_lock);
222 schedule_work(&xfrm_state_gc_work);
223}
224EXPORT_SYMBOL(__xfrm_state_destroy);
225
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800226int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700228 int err = -ESRCH;
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 if (x->km.state != XFRM_STATE_DEAD) {
231 x->km.state = XFRM_STATE_DEAD;
232 spin_lock(&xfrm_state_lock);
233 list_del(&x->bydst);
Herbert Xu21380b82006-02-22 14:47:13 -0800234 __xfrm_state_put(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if (x->id.spi) {
236 list_del(&x->byspi);
Herbert Xu21380b82006-02-22 14:47:13 -0800237 __xfrm_state_put(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 }
239 spin_unlock(&xfrm_state_lock);
240 if (del_timer(&x->timer))
Herbert Xu21380b82006-02-22 14:47:13 -0800241 __xfrm_state_put(x);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800242 if (del_timer(&x->rtimer))
243 __xfrm_state_put(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 /* The number two in this test is the reference
246 * mentioned in the comment below plus the reference
247 * our caller holds. A larger value means that
248 * there are DSTs attached to this xfrm_state.
249 */
250 if (atomic_read(&x->refcnt) > 2) {
251 xfrm_state_gc_flush_bundles = 1;
252 schedule_work(&xfrm_state_gc_work);
253 }
254
255 /* All xfrm_state objects are created by xfrm_state_alloc.
256 * The xfrm_state_alloc call gives a reference, and that
257 * is what we are dropping here.
258 */
Herbert Xu21380b82006-02-22 14:47:13 -0800259 __xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700260 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700262
263 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800265EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700267int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700269 int err;
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700272 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700274
275 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277EXPORT_SYMBOL(xfrm_state_delete);
278
279void xfrm_state_flush(u8 proto)
280{
281 int i;
282 struct xfrm_state *x;
283
284 spin_lock_bh(&xfrm_state_lock);
285 for (i = 0; i < XFRM_DST_HSIZE; i++) {
286restart:
287 list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
288 if (!xfrm_state_kern(x) &&
289 (proto == IPSEC_PROTO_ANY || x->id.proto == proto)) {
290 xfrm_state_hold(x);
291 spin_unlock_bh(&xfrm_state_lock);
292
293 xfrm_state_delete(x);
294 xfrm_state_put(x);
295
296 spin_lock_bh(&xfrm_state_lock);
297 goto restart;
298 }
299 }
300 }
301 spin_unlock_bh(&xfrm_state_lock);
302 wake_up(&km_waitq);
303}
304EXPORT_SYMBOL(xfrm_state_flush);
305
306static int
307xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
308 struct xfrm_tmpl *tmpl,
309 xfrm_address_t *daddr, xfrm_address_t *saddr,
310 unsigned short family)
311{
312 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
313 if (!afinfo)
314 return -1;
315 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
316 xfrm_state_put_afinfo(afinfo);
317 return 0;
318}
319
320struct xfrm_state *
321xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
322 struct flowi *fl, struct xfrm_tmpl *tmpl,
323 struct xfrm_policy *pol, int *err,
324 unsigned short family)
325{
326 unsigned h = xfrm_dst_hash(daddr, family);
327 struct xfrm_state *x, *x0;
328 int acquire_in_progress = 0;
329 int error = 0;
330 struct xfrm_state *best = NULL;
331 struct xfrm_state_afinfo *afinfo;
332
333 afinfo = xfrm_state_get_afinfo(family);
334 if (afinfo == NULL) {
335 *err = -EAFNOSUPPORT;
336 return NULL;
337 }
338
339 spin_lock_bh(&xfrm_state_lock);
340 list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
341 if (x->props.family == family &&
342 x->props.reqid == tmpl->reqid &&
343 xfrm_state_addr_check(x, daddr, saddr, family) &&
344 tmpl->mode == x->props.mode &&
345 tmpl->id.proto == x->id.proto &&
346 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
347 /* Resolution logic:
348 1. There is a valid state with matching selector.
349 Done.
350 2. Valid state with inappropriate selector. Skip.
351
352 Entering area of "sysdeps".
353
354 3. If state is not valid, selector is temporary,
355 it selects only session which triggered
356 previous resolution. Key manager will do
357 something to install a state with proper
358 selector.
359 */
360 if (x->km.state == XFRM_STATE_VALID) {
Trent Jaegerdf718372005-12-13 23:12:27 -0800361 if (!xfrm_selector_match(&x->sel, fl, family) ||
362 !xfrm_sec_ctx_match(pol->security, x->security))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 continue;
364 if (!best ||
365 best->km.dying > x->km.dying ||
366 (best->km.dying == x->km.dying &&
367 best->curlft.add_time < x->curlft.add_time))
368 best = x;
369 } else if (x->km.state == XFRM_STATE_ACQ) {
370 acquire_in_progress = 1;
371 } else if (x->km.state == XFRM_STATE_ERROR ||
372 x->km.state == XFRM_STATE_EXPIRED) {
Trent Jaegerdf718372005-12-13 23:12:27 -0800373 if (xfrm_selector_match(&x->sel, fl, family) &&
374 xfrm_sec_ctx_match(pol->security, x->security))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 error = -ESRCH;
376 }
377 }
378 }
379
380 x = best;
381 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700382 if (tmpl->id.spi &&
383 (x0 = afinfo->state_lookup(daddr, tmpl->id.spi,
384 tmpl->id.proto)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 xfrm_state_put(x0);
386 error = -EEXIST;
387 goto out;
388 }
389 x = xfrm_state_alloc();
390 if (x == NULL) {
391 error = -ENOMEM;
392 goto out;
393 }
394 /* Initialize temporary selector matching only
395 * to current session. */
396 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
397
398 if (km_query(x, tmpl, pol) == 0) {
399 x->km.state = XFRM_STATE_ACQ;
400 list_add_tail(&x->bydst, xfrm_state_bydst+h);
401 xfrm_state_hold(x);
402 if (x->id.spi) {
403 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
404 list_add(&x->byspi, xfrm_state_byspi+h);
405 xfrm_state_hold(x);
406 }
407 x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
408 xfrm_state_hold(x);
409 x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
410 add_timer(&x->timer);
411 } else {
412 x->km.state = XFRM_STATE_DEAD;
413 xfrm_state_put(x);
414 x = NULL;
415 error = -ESRCH;
416 }
417 }
418out:
419 if (x)
420 xfrm_state_hold(x);
421 else
422 *err = acquire_in_progress ? -EAGAIN : error;
423 spin_unlock_bh(&xfrm_state_lock);
424 xfrm_state_put_afinfo(afinfo);
425 return x;
426}
427
428static void __xfrm_state_insert(struct xfrm_state *x)
429{
430 unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family);
431
432 list_add(&x->bydst, xfrm_state_bydst+h);
433 xfrm_state_hold(x);
434
435 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
436
437 list_add(&x->byspi, xfrm_state_byspi+h);
438 xfrm_state_hold(x);
439
440 if (!mod_timer(&x->timer, jiffies + HZ))
441 xfrm_state_hold(x);
442
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800443 if (x->replay_maxage &&
444 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
445 xfrm_state_hold(x);
446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 wake_up(&km_waitq);
448}
449
450void xfrm_state_insert(struct xfrm_state *x)
451{
452 spin_lock_bh(&xfrm_state_lock);
453 __xfrm_state_insert(x);
454 spin_unlock_bh(&xfrm_state_lock);
David S. Miller399c1802005-12-19 14:23:23 -0800455
456 xfrm_flush_all_bundles();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458EXPORT_SYMBOL(xfrm_state_insert);
459
460static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
461
462int xfrm_state_add(struct xfrm_state *x)
463{
464 struct xfrm_state_afinfo *afinfo;
465 struct xfrm_state *x1;
466 int family;
467 int err;
468
469 family = x->props.family;
470 afinfo = xfrm_state_get_afinfo(family);
471 if (unlikely(afinfo == NULL))
472 return -EAFNOSUPPORT;
473
474 spin_lock_bh(&xfrm_state_lock);
475
476 x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
477 if (x1) {
478 xfrm_state_put(x1);
479 x1 = NULL;
480 err = -EEXIST;
481 goto out;
482 }
483
484 if (x->km.seq) {
485 x1 = __xfrm_find_acq_byseq(x->km.seq);
486 if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) {
487 xfrm_state_put(x1);
488 x1 = NULL;
489 }
490 }
491
492 if (!x1)
493 x1 = afinfo->find_acq(
494 x->props.mode, x->props.reqid, x->id.proto,
495 &x->id.daddr, &x->props.saddr, 0);
496
497 __xfrm_state_insert(x);
498 err = 0;
499
500out:
501 spin_unlock_bh(&xfrm_state_lock);
502 xfrm_state_put_afinfo(afinfo);
503
David S. Miller399c1802005-12-19 14:23:23 -0800504 if (!err)
505 xfrm_flush_all_bundles();
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (x1) {
508 xfrm_state_delete(x1);
509 xfrm_state_put(x1);
510 }
511
512 return err;
513}
514EXPORT_SYMBOL(xfrm_state_add);
515
516int xfrm_state_update(struct xfrm_state *x)
517{
518 struct xfrm_state_afinfo *afinfo;
519 struct xfrm_state *x1;
520 int err;
521
522 afinfo = xfrm_state_get_afinfo(x->props.family);
523 if (unlikely(afinfo == NULL))
524 return -EAFNOSUPPORT;
525
526 spin_lock_bh(&xfrm_state_lock);
527 x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
528
529 err = -ESRCH;
530 if (!x1)
531 goto out;
532
533 if (xfrm_state_kern(x1)) {
534 xfrm_state_put(x1);
535 err = -EEXIST;
536 goto out;
537 }
538
539 if (x1->km.state == XFRM_STATE_ACQ) {
540 __xfrm_state_insert(x);
541 x = NULL;
542 }
543 err = 0;
544
545out:
546 spin_unlock_bh(&xfrm_state_lock);
547 xfrm_state_put_afinfo(afinfo);
548
549 if (err)
550 return err;
551
552 if (!x) {
553 xfrm_state_delete(x1);
554 xfrm_state_put(x1);
555 return 0;
556 }
557
558 err = -EINVAL;
559 spin_lock_bh(&x1->lock);
560 if (likely(x1->km.state == XFRM_STATE_VALID)) {
561 if (x->encap && x1->encap)
562 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
563 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
564 x1->km.dying = 0;
565
566 if (!mod_timer(&x1->timer, jiffies + HZ))
567 xfrm_state_hold(x1);
568 if (x1->curlft.use_time)
569 xfrm_state_check_expire(x1);
570
571 err = 0;
572 }
573 spin_unlock_bh(&x1->lock);
574
575 xfrm_state_put(x1);
576
577 return err;
578}
579EXPORT_SYMBOL(xfrm_state_update);
580
581int xfrm_state_check_expire(struct xfrm_state *x)
582{
583 if (!x->curlft.use_time)
584 x->curlft.use_time = (unsigned long)xtime.tv_sec;
585
586 if (x->km.state != XFRM_STATE_VALID)
587 return -EINVAL;
588
589 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
590 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -0700591 x->km.state = XFRM_STATE_EXPIRED;
592 if (!mod_timer(&x->timer, jiffies))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 xfrm_state_hold(x);
594 return -EINVAL;
595 }
596
597 if (!x->km.dying &&
598 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -0700599 x->curlft.packets >= x->lft.soft_packet_limit)) {
600 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800601 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -0700602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 return 0;
604}
605EXPORT_SYMBOL(xfrm_state_check_expire);
606
607static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
608{
609 int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev)
610 - skb_headroom(skb);
611
612 if (nhead > 0)
613 return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
614
615 /* Check tail too... */
616 return 0;
617}
618
619int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
620{
621 int err = xfrm_state_check_expire(x);
622 if (err < 0)
623 goto err;
624 err = xfrm_state_check_space(x, skb);
625err:
626 return err;
627}
628EXPORT_SYMBOL(xfrm_state_check);
629
630struct xfrm_state *
631xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
632 unsigned short family)
633{
634 struct xfrm_state *x;
635 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
636 if (!afinfo)
637 return NULL;
638
639 spin_lock_bh(&xfrm_state_lock);
640 x = afinfo->state_lookup(daddr, spi, proto);
641 spin_unlock_bh(&xfrm_state_lock);
642 xfrm_state_put_afinfo(afinfo);
643 return x;
644}
645EXPORT_SYMBOL(xfrm_state_lookup);
646
647struct xfrm_state *
648xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
649 xfrm_address_t *daddr, xfrm_address_t *saddr,
650 int create, unsigned short family)
651{
652 struct xfrm_state *x;
653 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
654 if (!afinfo)
655 return NULL;
656
657 spin_lock_bh(&xfrm_state_lock);
658 x = afinfo->find_acq(mode, reqid, proto, daddr, saddr, create);
659 spin_unlock_bh(&xfrm_state_lock);
660 xfrm_state_put_afinfo(afinfo);
661 return x;
662}
663EXPORT_SYMBOL(xfrm_find_acq);
664
665/* Silly enough, but I'm lazy to build resolution list */
666
667static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
668{
669 int i;
670 struct xfrm_state *x;
671
672 for (i = 0; i < XFRM_DST_HSIZE; i++) {
673 list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
674 if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) {
675 xfrm_state_hold(x);
676 return x;
677 }
678 }
679 }
680 return NULL;
681}
682
683struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
684{
685 struct xfrm_state *x;
686
687 spin_lock_bh(&xfrm_state_lock);
688 x = __xfrm_find_acq_byseq(seq);
689 spin_unlock_bh(&xfrm_state_lock);
690 return x;
691}
692EXPORT_SYMBOL(xfrm_find_acq_byseq);
693
694u32 xfrm_get_acqseq(void)
695{
696 u32 res;
697 static u32 acqseq;
698 static DEFINE_SPINLOCK(acqseq_lock);
699
700 spin_lock_bh(&acqseq_lock);
701 res = (++acqseq ? : ++acqseq);
702 spin_unlock_bh(&acqseq_lock);
703 return res;
704}
705EXPORT_SYMBOL(xfrm_get_acqseq);
706
707void
708xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
709{
710 u32 h;
711 struct xfrm_state *x0;
712
713 if (x->id.spi)
714 return;
715
716 if (minspi == maxspi) {
717 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
718 if (x0) {
719 xfrm_state_put(x0);
720 return;
721 }
722 x->id.spi = minspi;
723 } else {
724 u32 spi = 0;
725 minspi = ntohl(minspi);
726 maxspi = ntohl(maxspi);
727 for (h=0; h<maxspi-minspi+1; h++) {
728 spi = minspi + net_random()%(maxspi-minspi+1);
729 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
730 if (x0 == NULL) {
731 x->id.spi = htonl(spi);
732 break;
733 }
734 xfrm_state_put(x0);
735 }
736 }
737 if (x->id.spi) {
738 spin_lock_bh(&xfrm_state_lock);
739 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
740 list_add(&x->byspi, xfrm_state_byspi+h);
741 xfrm_state_hold(x);
742 spin_unlock_bh(&xfrm_state_lock);
743 wake_up(&km_waitq);
744 }
745}
746EXPORT_SYMBOL(xfrm_alloc_spi);
747
748int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
749 void *data)
750{
751 int i;
752 struct xfrm_state *x;
753 int count = 0;
754 int err = 0;
755
756 spin_lock_bh(&xfrm_state_lock);
757 for (i = 0; i < XFRM_DST_HSIZE; i++) {
758 list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
759 if (proto == IPSEC_PROTO_ANY || x->id.proto == proto)
760 count++;
761 }
762 }
763 if (count == 0) {
764 err = -ENOENT;
765 goto out;
766 }
767
768 for (i = 0; i < XFRM_DST_HSIZE; i++) {
769 list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
770 if (proto != IPSEC_PROTO_ANY && x->id.proto != proto)
771 continue;
772 err = func(x, --count, data);
773 if (err)
774 goto out;
775 }
776 }
777out:
778 spin_unlock_bh(&xfrm_state_lock);
779 return err;
780}
781EXPORT_SYMBOL(xfrm_state_walk);
782
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800783
784void xfrm_replay_notify(struct xfrm_state *x, int event)
785{
786 struct km_event c;
787 /* we send notify messages in case
788 * 1. we updated on of the sequence numbers, and the seqno difference
789 * is at least x->replay_maxdiff, in this case we also update the
790 * timeout of our timer function
791 * 2. if x->replay_maxage has elapsed since last update,
792 * and there were changes
793 *
794 * The state structure must be locked!
795 */
796
797 switch (event) {
798 case XFRM_REPLAY_UPDATE:
799 if (x->replay_maxdiff &&
800 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
801 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))
802 return;
803
804 break;
805
806 case XFRM_REPLAY_TIMEOUT:
807 if ((x->replay.seq == x->preplay.seq) &&
808 (x->replay.bitmap == x->preplay.bitmap) &&
809 (x->replay.oseq == x->preplay.oseq))
810 return;
811
812 break;
813 }
814
815 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
816 c.event = XFRM_MSG_NEWAE;
817 c.data.aevent = event;
818 km_state_notify(x, &c);
819
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800820 if (x->replay_maxage &&
821 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
822 xfrm_state_hold(x);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800823}
824
825static void xfrm_replay_timer_handler(unsigned long data)
826{
827 struct xfrm_state *x = (struct xfrm_state*)data;
828
829 spin_lock(&x->lock);
830
831 if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID)
832 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
833
834 spin_unlock(&x->lock);
835}
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837int xfrm_replay_check(struct xfrm_state *x, u32 seq)
838{
839 u32 diff;
840
841 seq = ntohl(seq);
842
843 if (unlikely(seq == 0))
844 return -EINVAL;
845
846 if (likely(seq > x->replay.seq))
847 return 0;
848
849 diff = x->replay.seq - seq;
850 if (diff >= x->props.replay_window) {
851 x->stats.replay_window++;
852 return -EINVAL;
853 }
854
855 if (x->replay.bitmap & (1U << diff)) {
856 x->stats.replay++;
857 return -EINVAL;
858 }
859 return 0;
860}
861EXPORT_SYMBOL(xfrm_replay_check);
862
863void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
864{
865 u32 diff;
866
867 seq = ntohl(seq);
868
869 if (seq > x->replay.seq) {
870 diff = seq - x->replay.seq;
871 if (diff < x->props.replay_window)
872 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
873 else
874 x->replay.bitmap = 1;
875 x->replay.seq = seq;
876 } else {
877 diff = x->replay.seq - seq;
878 x->replay.bitmap |= (1U << diff);
879 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800880
881 if (xfrm_aevent_is_on())
882 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883}
884EXPORT_SYMBOL(xfrm_replay_advance);
885
886static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
887static DEFINE_RWLOCK(xfrm_km_lock);
888
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700889void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
891 struct xfrm_mgr *km;
892
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700893 read_lock(&xfrm_km_lock);
894 list_for_each_entry(km, &xfrm_km_list, list)
895 if (km->notify_policy)
896 km->notify_policy(xp, dir, c);
897 read_unlock(&xfrm_km_lock);
898}
899
900void km_state_notify(struct xfrm_state *x, struct km_event *c)
901{
902 struct xfrm_mgr *km;
903 read_lock(&xfrm_km_lock);
904 list_for_each_entry(km, &xfrm_km_list, list)
905 if (km->notify)
906 km->notify(x, c);
907 read_unlock(&xfrm_km_lock);
908}
909
910EXPORT_SYMBOL(km_policy_notify);
911EXPORT_SYMBOL(km_state_notify);
912
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800913void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700914{
915 struct km_event c;
916
Herbert Xubf088672005-06-18 22:44:00 -0700917 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800918 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -0700919 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700920 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 if (hard)
923 wake_up(&km_waitq);
924}
925
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800926EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700927/*
928 * We send to all registered managers regardless of failure
929 * We are happy with one success
930*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800931int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700933 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 struct xfrm_mgr *km;
935
936 read_lock(&xfrm_km_lock);
937 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700938 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
939 if (!acqret)
940 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
942 read_unlock(&xfrm_km_lock);
943 return err;
944}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800945EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
948{
949 int err = -EINVAL;
950 struct xfrm_mgr *km;
951
952 read_lock(&xfrm_km_lock);
953 list_for_each_entry(km, &xfrm_km_list, list) {
954 if (km->new_mapping)
955 err = km->new_mapping(x, ipaddr, sport);
956 if (!err)
957 break;
958 }
959 read_unlock(&xfrm_km_lock);
960 return err;
961}
962EXPORT_SYMBOL(km_new_mapping);
963
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -0800964void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700966 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Herbert Xubf088672005-06-18 22:44:00 -0700968 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -0800969 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -0700970 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700971 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
973 if (hard)
974 wake_up(&km_waitq);
975}
976
977int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
978{
979 int err;
980 u8 *data;
981 struct xfrm_mgr *km;
982 struct xfrm_policy *pol = NULL;
983
984 if (optlen <= 0 || optlen > PAGE_SIZE)
985 return -EMSGSIZE;
986
987 data = kmalloc(optlen, GFP_KERNEL);
988 if (!data)
989 return -ENOMEM;
990
991 err = -EFAULT;
992 if (copy_from_user(data, optval, optlen))
993 goto out;
994
995 err = -EINVAL;
996 read_lock(&xfrm_km_lock);
997 list_for_each_entry(km, &xfrm_km_list, list) {
998 pol = km->compile_policy(sk->sk_family, optname, data,
999 optlen, &err);
1000 if (err >= 0)
1001 break;
1002 }
1003 read_unlock(&xfrm_km_lock);
1004
1005 if (err >= 0) {
1006 xfrm_sk_policy_insert(sk, err, pol);
1007 xfrm_pol_put(pol);
1008 err = 0;
1009 }
1010
1011out:
1012 kfree(data);
1013 return err;
1014}
1015EXPORT_SYMBOL(xfrm_user_policy);
1016
1017int xfrm_register_km(struct xfrm_mgr *km)
1018{
1019 write_lock_bh(&xfrm_km_lock);
1020 list_add_tail(&km->list, &xfrm_km_list);
1021 write_unlock_bh(&xfrm_km_lock);
1022 return 0;
1023}
1024EXPORT_SYMBOL(xfrm_register_km);
1025
1026int xfrm_unregister_km(struct xfrm_mgr *km)
1027{
1028 write_lock_bh(&xfrm_km_lock);
1029 list_del(&km->list);
1030 write_unlock_bh(&xfrm_km_lock);
1031 return 0;
1032}
1033EXPORT_SYMBOL(xfrm_unregister_km);
1034
1035int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1036{
1037 int err = 0;
1038 if (unlikely(afinfo == NULL))
1039 return -EINVAL;
1040 if (unlikely(afinfo->family >= NPROTO))
1041 return -EAFNOSUPPORT;
1042 write_lock(&xfrm_state_afinfo_lock);
1043 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1044 err = -ENOBUFS;
1045 else {
1046 afinfo->state_bydst = xfrm_state_bydst;
1047 afinfo->state_byspi = xfrm_state_byspi;
1048 xfrm_state_afinfo[afinfo->family] = afinfo;
1049 }
1050 write_unlock(&xfrm_state_afinfo_lock);
1051 return err;
1052}
1053EXPORT_SYMBOL(xfrm_state_register_afinfo);
1054
1055int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1056{
1057 int err = 0;
1058 if (unlikely(afinfo == NULL))
1059 return -EINVAL;
1060 if (unlikely(afinfo->family >= NPROTO))
1061 return -EAFNOSUPPORT;
1062 write_lock(&xfrm_state_afinfo_lock);
1063 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1064 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1065 err = -EINVAL;
1066 else {
1067 xfrm_state_afinfo[afinfo->family] = NULL;
1068 afinfo->state_byspi = NULL;
1069 afinfo->state_bydst = NULL;
1070 }
1071 }
1072 write_unlock(&xfrm_state_afinfo_lock);
1073 return err;
1074}
1075EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1076
1077static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
1078{
1079 struct xfrm_state_afinfo *afinfo;
1080 if (unlikely(family >= NPROTO))
1081 return NULL;
1082 read_lock(&xfrm_state_afinfo_lock);
1083 afinfo = xfrm_state_afinfo[family];
1084 if (likely(afinfo != NULL))
1085 read_lock(&afinfo->lock);
1086 read_unlock(&xfrm_state_afinfo_lock);
1087 return afinfo;
1088}
1089
1090static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
1091{
1092 if (unlikely(afinfo == NULL))
1093 return;
1094 read_unlock(&afinfo->lock);
1095}
1096
1097/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1098void xfrm_state_delete_tunnel(struct xfrm_state *x)
1099{
1100 if (x->tunnel) {
1101 struct xfrm_state *t = x->tunnel;
1102
1103 if (atomic_read(&t->tunnel_users) == 2)
1104 xfrm_state_delete(t);
1105 atomic_dec(&t->tunnel_users);
1106 xfrm_state_put(t);
1107 x->tunnel = NULL;
1108 }
1109}
1110EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1111
Herbert Xu80b30c12005-10-15 10:58:30 +10001112/*
1113 * This function is NOT optimal. For example, with ESP it will give an
1114 * MTU that's usually two bytes short of being optimal. However, it will
1115 * usually give an answer that's a multiple of 4 provided the input is
1116 * also a multiple of 4.
1117 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1119{
1120 int res = mtu;
1121
1122 res -= x->props.header_len;
1123
1124 for (;;) {
1125 int m = res;
1126
1127 if (m < 68)
1128 return 68;
1129
1130 spin_lock_bh(&x->lock);
1131 if (x->km.state == XFRM_STATE_VALID &&
1132 x->type && x->type->get_max_size)
1133 m = x->type->get_max_size(x, m);
1134 else
1135 m += x->props.header_len;
1136 spin_unlock_bh(&x->lock);
1137
1138 if (m <= mtu)
1139 break;
1140 res -= (m - mtu);
1141 }
1142
1143 return res;
1144}
1145
1146EXPORT_SYMBOL(xfrm_state_mtu);
Herbert Xu72cb6962005-06-20 13:18:08 -07001147
1148int xfrm_init_state(struct xfrm_state *x)
1149{
Herbert Xud094cd82005-06-20 13:19:41 -07001150 struct xfrm_state_afinfo *afinfo;
1151 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001152 int err;
1153
Herbert Xud094cd82005-06-20 13:19:41 -07001154 err = -EAFNOSUPPORT;
1155 afinfo = xfrm_state_get_afinfo(family);
1156 if (!afinfo)
1157 goto error;
1158
1159 err = 0;
1160 if (afinfo->init_flags)
1161 err = afinfo->init_flags(x);
1162
1163 xfrm_state_put_afinfo(afinfo);
1164
1165 if (err)
1166 goto error;
1167
1168 err = -EPROTONOSUPPORT;
1169 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07001170 if (x->type == NULL)
1171 goto error;
1172
1173 err = x->type->init_state(x);
1174 if (err)
1175 goto error;
1176
1177 x->km.state = XFRM_STATE_VALID;
1178
1179error:
1180 return err;
1181}
1182
1183EXPORT_SYMBOL(xfrm_init_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
1185void __init xfrm_state_init(void)
1186{
1187 int i;
1188
1189 for (i=0; i<XFRM_DST_HSIZE; i++) {
1190 INIT_LIST_HEAD(&xfrm_state_bydst[i]);
1191 INIT_LIST_HEAD(&xfrm_state_byspi[i]);
1192 }
1193 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
1194}
1195