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