blob: fe3c8c38d5e1292a69989d13ee03304513d2af3a [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;
David S. Millera70fcb02006-03-20 19:18:52 -080027EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
28
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -080029u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE;
David S. Millera70fcb02006-03-20 19:18:52 -080030EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032/* Each xfrm_state may be linked to two tables:
33
34 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
36 destination/tunnel endpoint. (output)
37 */
38
39static DEFINE_SPINLOCK(xfrm_state_lock);
40
David S. Milleredcd5822006-08-24 00:42:45 -070041#define XFRM_DST_HSIZE 1024
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043/* Hash table to find appropriate SA towards given target (endpoint
44 * of tunnel or destination of transport mode) allowed by selector.
45 *
46 * Main use is finding SA after policy selected tunnel or transport mode.
47 * Also, it can be used by ah/esp icmp error handler to find offending SA.
48 */
David S. Miller8f126e32006-08-24 02:45:07 -070049static struct hlist_head xfrm_state_bydst[XFRM_DST_HSIZE];
50static struct hlist_head xfrm_state_bysrc[XFRM_DST_HSIZE];
51static struct hlist_head xfrm_state_byspi[XFRM_DST_HSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
David S. Miller27708342006-08-24 00:13:10 -070053static __inline__
David S. Milleredcd5822006-08-24 00:42:45 -070054unsigned __xfrm4_dst_hash(xfrm_address_t *addr)
55{
56 unsigned h;
57 h = ntohl(addr->a4);
58 h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
59 return h;
60}
61
62static __inline__
63unsigned __xfrm6_dst_hash(xfrm_address_t *addr)
64{
65 unsigned h;
66 h = ntohl(addr->a6[2]^addr->a6[3]);
67 h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
68 return h;
69}
70
71static __inline__
72unsigned __xfrm4_src_hash(xfrm_address_t *addr)
73{
74 return __xfrm4_dst_hash(addr);
75}
76
77static __inline__
78unsigned __xfrm6_src_hash(xfrm_address_t *addr)
79{
80 return __xfrm6_dst_hash(addr);
81}
82
83static __inline__
84unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family)
85{
86 switch (family) {
87 case AF_INET:
88 return __xfrm4_src_hash(addr);
89 case AF_INET6:
90 return __xfrm6_src_hash(addr);
91 }
92 return 0;
93}
94
95static __inline__
David S. Miller27708342006-08-24 00:13:10 -070096unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family)
97{
98 switch (family) {
99 case AF_INET:
100 return __xfrm4_dst_hash(addr);
101 case AF_INET6:
102 return __xfrm6_dst_hash(addr);
103 }
104 return 0;
105}
106
David S. Milleredcd5822006-08-24 00:42:45 -0700107static __inline__
108unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
109{
110 unsigned h;
111 h = ntohl(addr->a4^spi^proto);
112 h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
113 return h;
114}
115
116static __inline__
117unsigned __xfrm6_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
118{
119 unsigned h;
120 h = ntohl(addr->a6[2]^addr->a6[3]^spi^proto);
121 h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
122 return h;
123}
124
125static __inline__
126unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family)
127{
128 switch (family) {
129 case AF_INET:
130 return __xfrm4_spi_hash(addr, spi, proto);
131 case AF_INET6:
132 return __xfrm6_spi_hash(addr, spi, proto);
133 }
134 return 0; /*XXX*/
135}
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137DECLARE_WAIT_QUEUE_HEAD(km_waitq);
138EXPORT_SYMBOL(km_waitq);
139
140static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
141static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
142
143static struct work_struct xfrm_state_gc_work;
David S. Miller8f126e32006-08-24 02:45:07 -0700144static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145static DEFINE_SPINLOCK(xfrm_state_gc_lock);
146
147static int xfrm_state_gc_flush_bundles;
148
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800149int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
152static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
153
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800154int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800155void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157static void xfrm_state_gc_destroy(struct xfrm_state *x)
158{
159 if (del_timer(&x->timer))
160 BUG();
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800161 if (del_timer(&x->rtimer))
162 BUG();
Jesper Juhla51482b2005-11-08 09:41:34 -0800163 kfree(x->aalg);
164 kfree(x->ealg);
165 kfree(x->calg);
166 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700167 kfree(x->coaddr);
Herbert Xub59f45d2006-05-27 23:05:54 -0700168 if (x->mode)
169 xfrm_put_mode(x->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 if (x->type) {
171 x->type->destructor(x);
172 xfrm_put_type(x->type);
173 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800174 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 kfree(x);
176}
177
178static void xfrm_state_gc_task(void *data)
179{
180 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700181 struct hlist_node *entry, *tmp;
182 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184 if (xfrm_state_gc_flush_bundles) {
185 xfrm_state_gc_flush_bundles = 0;
186 xfrm_flush_bundles();
187 }
188
189 spin_lock_bh(&xfrm_state_gc_lock);
David S. Miller8f126e32006-08-24 02:45:07 -0700190 gc_list.first = xfrm_state_gc_list.first;
191 INIT_HLIST_HEAD(&xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 spin_unlock_bh(&xfrm_state_gc_lock);
193
David S. Miller8f126e32006-08-24 02:45:07 -0700194 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 wake_up(&km_waitq);
198}
199
200static inline unsigned long make_jiffies(long secs)
201{
202 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
203 return MAX_SCHEDULE_TIMEOUT-1;
204 else
205 return secs*HZ;
206}
207
208static void xfrm_timer_handler(unsigned long data)
209{
210 struct xfrm_state *x = (struct xfrm_state*)data;
211 unsigned long now = (unsigned long)xtime.tv_sec;
212 long next = LONG_MAX;
213 int warn = 0;
214
215 spin_lock(&x->lock);
216 if (x->km.state == XFRM_STATE_DEAD)
217 goto out;
218 if (x->km.state == XFRM_STATE_EXPIRED)
219 goto expired;
220 if (x->lft.hard_add_expires_seconds) {
221 long tmo = x->lft.hard_add_expires_seconds +
222 x->curlft.add_time - now;
223 if (tmo <= 0)
224 goto expired;
225 if (tmo < next)
226 next = tmo;
227 }
228 if (x->lft.hard_use_expires_seconds) {
229 long tmo = x->lft.hard_use_expires_seconds +
230 (x->curlft.use_time ? : now) - now;
231 if (tmo <= 0)
232 goto expired;
233 if (tmo < next)
234 next = tmo;
235 }
236 if (x->km.dying)
237 goto resched;
238 if (x->lft.soft_add_expires_seconds) {
239 long tmo = x->lft.soft_add_expires_seconds +
240 x->curlft.add_time - now;
241 if (tmo <= 0)
242 warn = 1;
243 else if (tmo < next)
244 next = tmo;
245 }
246 if (x->lft.soft_use_expires_seconds) {
247 long tmo = x->lft.soft_use_expires_seconds +
248 (x->curlft.use_time ? : now) - now;
249 if (tmo <= 0)
250 warn = 1;
251 else if (tmo < next)
252 next = tmo;
253 }
254
Herbert Xu4666faa2005-06-18 22:43:22 -0700255 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800257 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258resched:
259 if (next != LONG_MAX &&
260 !mod_timer(&x->timer, jiffies + make_jiffies(next)))
261 xfrm_state_hold(x);
262 goto out;
263
264expired:
265 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
266 x->km.state = XFRM_STATE_EXPIRED;
267 wake_up(&km_waitq);
268 next = 2;
269 goto resched;
270 }
Herbert Xu4666faa2005-06-18 22:43:22 -0700271 if (!__xfrm_state_delete(x) && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800272 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274out:
275 spin_unlock(&x->lock);
276 xfrm_state_put(x);
277}
278
David S. Miller0ac84752006-03-20 19:18:23 -0800279static void xfrm_replay_timer_handler(unsigned long data);
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281struct xfrm_state *xfrm_state_alloc(void)
282{
283 struct xfrm_state *x;
284
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700285 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if (x) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 atomic_set(&x->refcnt, 1);
289 atomic_set(&x->tunnel_users, 0);
David S. Miller8f126e32006-08-24 02:45:07 -0700290 INIT_HLIST_NODE(&x->bydst);
291 INIT_HLIST_NODE(&x->bysrc);
292 INIT_HLIST_NODE(&x->byspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 init_timer(&x->timer);
294 x->timer.function = xfrm_timer_handler;
295 x->timer.data = (unsigned long)x;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800296 init_timer(&x->rtimer);
297 x->rtimer.function = xfrm_replay_timer_handler;
298 x->rtimer.data = (unsigned long)x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 x->curlft.add_time = (unsigned long)xtime.tv_sec;
300 x->lft.soft_byte_limit = XFRM_INF;
301 x->lft.soft_packet_limit = XFRM_INF;
302 x->lft.hard_byte_limit = XFRM_INF;
303 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800304 x->replay_maxage = 0;
305 x->replay_maxdiff = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 spin_lock_init(&x->lock);
307 }
308 return x;
309}
310EXPORT_SYMBOL(xfrm_state_alloc);
311
312void __xfrm_state_destroy(struct xfrm_state *x)
313{
314 BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
315
316 spin_lock_bh(&xfrm_state_gc_lock);
David S. Miller8f126e32006-08-24 02:45:07 -0700317 hlist_add_head(&x->bydst, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 spin_unlock_bh(&xfrm_state_gc_lock);
319 schedule_work(&xfrm_state_gc_work);
320}
321EXPORT_SYMBOL(__xfrm_state_destroy);
322
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800323int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700325 int err = -ESRCH;
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 if (x->km.state != XFRM_STATE_DEAD) {
328 x->km.state = XFRM_STATE_DEAD;
329 spin_lock(&xfrm_state_lock);
David S. Miller8f126e32006-08-24 02:45:07 -0700330 hlist_del(&x->bydst);
Herbert Xu21380b82006-02-22 14:47:13 -0800331 __xfrm_state_put(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700332 hlist_del(&x->bysrc);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700333 __xfrm_state_put(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 if (x->id.spi) {
David S. Miller8f126e32006-08-24 02:45:07 -0700335 hlist_del(&x->byspi);
Herbert Xu21380b82006-02-22 14:47:13 -0800336 __xfrm_state_put(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 }
338 spin_unlock(&xfrm_state_lock);
339 if (del_timer(&x->timer))
Herbert Xu21380b82006-02-22 14:47:13 -0800340 __xfrm_state_put(x);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800341 if (del_timer(&x->rtimer))
342 __xfrm_state_put(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 /* The number two in this test is the reference
345 * mentioned in the comment below plus the reference
346 * our caller holds. A larger value means that
347 * there are DSTs attached to this xfrm_state.
348 */
349 if (atomic_read(&x->refcnt) > 2) {
350 xfrm_state_gc_flush_bundles = 1;
351 schedule_work(&xfrm_state_gc_work);
352 }
353
354 /* All xfrm_state objects are created by xfrm_state_alloc.
355 * The xfrm_state_alloc call gives a reference, and that
356 * is what we are dropping here.
357 */
Herbert Xu21380b82006-02-22 14:47:13 -0800358 __xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700359 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700361
362 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800364EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700366int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700368 int err;
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700371 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700373
374 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376EXPORT_SYMBOL(xfrm_state_delete);
377
378void xfrm_state_flush(u8 proto)
379{
380 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
382 spin_lock_bh(&xfrm_state_lock);
383 for (i = 0; i < XFRM_DST_HSIZE; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700384 struct hlist_node *entry;
385 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386restart:
David S. Miller8f126e32006-08-24 02:45:07 -0700387 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700389 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 xfrm_state_hold(x);
391 spin_unlock_bh(&xfrm_state_lock);
392
393 xfrm_state_delete(x);
394 xfrm_state_put(x);
395
396 spin_lock_bh(&xfrm_state_lock);
397 goto restart;
398 }
399 }
400 }
401 spin_unlock_bh(&xfrm_state_lock);
402 wake_up(&km_waitq);
403}
404EXPORT_SYMBOL(xfrm_state_flush);
405
406static int
407xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
408 struct xfrm_tmpl *tmpl,
409 xfrm_address_t *daddr, xfrm_address_t *saddr,
410 unsigned short family)
411{
412 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
413 if (!afinfo)
414 return -1;
415 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
416 xfrm_state_put_afinfo(afinfo);
417 return 0;
418}
419
David S. Milleredcd5822006-08-24 00:42:45 -0700420static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
421{
422 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
423 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700424 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700425
David S. Miller8f126e32006-08-24 02:45:07 -0700426 hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700427 if (x->props.family != family ||
428 x->id.spi != spi ||
429 x->id.proto != proto)
430 continue;
431
432 switch (family) {
433 case AF_INET:
434 if (x->id.daddr.a4 != daddr->a4)
435 continue;
436 break;
437 case AF_INET6:
438 if (!ipv6_addr_equal((struct in6_addr *)daddr,
439 (struct in6_addr *)
440 x->id.daddr.a6))
441 continue;
442 break;
443 };
444
445 xfrm_state_hold(x);
446 return x;
447 }
448
449 return NULL;
450}
451
452static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
453{
454 unsigned int h = xfrm_src_hash(saddr, family);
455 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700456 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700457
David S. Miller8f126e32006-08-24 02:45:07 -0700458 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700459 if (x->props.family != family ||
460 x->id.proto != proto)
461 continue;
462
463 switch (family) {
464 case AF_INET:
465 if (x->id.daddr.a4 != daddr->a4 ||
466 x->props.saddr.a4 != saddr->a4)
467 continue;
468 break;
469 case AF_INET6:
470 if (!ipv6_addr_equal((struct in6_addr *)daddr,
471 (struct in6_addr *)
472 x->id.daddr.a6) ||
473 !ipv6_addr_equal((struct in6_addr *)saddr,
474 (struct in6_addr *)
475 x->props.saddr.a6))
476 continue;
477 break;
478 };
479
480 xfrm_state_hold(x);
481 return x;
482 }
483
484 return NULL;
485}
486
487static inline struct xfrm_state *
488__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
489{
490 if (use_spi)
491 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
492 x->id.proto, family);
493 else
494 return __xfrm_state_lookup_byaddr(&x->id.daddr,
495 &x->props.saddr,
496 x->id.proto, family);
497}
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499struct xfrm_state *
500xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
501 struct flowi *fl, struct xfrm_tmpl *tmpl,
502 struct xfrm_policy *pol, int *err,
503 unsigned short family)
504{
David S. Miller8f126e32006-08-24 02:45:07 -0700505 unsigned int h = xfrm_dst_hash(daddr, family);
506 struct hlist_node *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct xfrm_state *x, *x0;
508 int acquire_in_progress = 0;
509 int error = 0;
510 struct xfrm_state *best = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 spin_lock_bh(&xfrm_state_lock);
David S. Miller8f126e32006-08-24 02:45:07 -0700513 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (x->props.family == family &&
515 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700516 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 xfrm_state_addr_check(x, daddr, saddr, family) &&
518 tmpl->mode == x->props.mode &&
519 tmpl->id.proto == x->id.proto &&
520 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
521 /* Resolution logic:
522 1. There is a valid state with matching selector.
523 Done.
524 2. Valid state with inappropriate selector. Skip.
525
526 Entering area of "sysdeps".
527
528 3. If state is not valid, selector is temporary,
529 it selects only session which triggered
530 previous resolution. Key manager will do
531 something to install a state with proper
532 selector.
533 */
534 if (x->km.state == XFRM_STATE_VALID) {
Trent Jaegerdf718372005-12-13 23:12:27 -0800535 if (!xfrm_selector_match(&x->sel, fl, family) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700536 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 continue;
538 if (!best ||
539 best->km.dying > x->km.dying ||
540 (best->km.dying == x->km.dying &&
541 best->curlft.add_time < x->curlft.add_time))
542 best = x;
543 } else if (x->km.state == XFRM_STATE_ACQ) {
544 acquire_in_progress = 1;
545 } else if (x->km.state == XFRM_STATE_ERROR ||
546 x->km.state == XFRM_STATE_EXPIRED) {
Trent Jaegerdf718372005-12-13 23:12:27 -0800547 if (xfrm_selector_match(&x->sel, fl, family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700548 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 error = -ESRCH;
550 }
551 }
552 }
553
554 x = best;
555 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700556 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700557 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
558 tmpl->id.proto, family)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 xfrm_state_put(x0);
560 error = -EEXIST;
561 goto out;
562 }
563 x = xfrm_state_alloc();
564 if (x == NULL) {
565 error = -ENOMEM;
566 goto out;
567 }
568 /* Initialize temporary selector matching only
569 * to current session. */
570 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
571
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700572 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
573 if (error) {
574 x->km.state = XFRM_STATE_DEAD;
575 xfrm_state_put(x);
576 x = NULL;
577 goto out;
578 }
579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 if (km_query(x, tmpl, pol) == 0) {
581 x->km.state = XFRM_STATE_ACQ;
David S. Miller8f126e32006-08-24 02:45:07 -0700582 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 xfrm_state_hold(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700584 h = xfrm_src_hash(saddr, family);
585 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700586 xfrm_state_hold(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 if (x->id.spi) {
588 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700589 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 xfrm_state_hold(x);
591 }
592 x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
593 xfrm_state_hold(x);
594 x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
595 add_timer(&x->timer);
596 } else {
597 x->km.state = XFRM_STATE_DEAD;
598 xfrm_state_put(x);
599 x = NULL;
600 error = -ESRCH;
601 }
602 }
603out:
604 if (x)
605 xfrm_state_hold(x);
606 else
607 *err = acquire_in_progress ? -EAGAIN : error;
608 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return x;
610}
611
612static void __xfrm_state_insert(struct xfrm_state *x)
613{
614 unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family);
615
David S. Miller8f126e32006-08-24 02:45:07 -0700616 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 xfrm_state_hold(x);
618
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700619 h = xfrm_src_hash(&x->props.saddr, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
David S. Miller8f126e32006-08-24 02:45:07 -0700621 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 xfrm_state_hold(x);
623
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700624 if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) {
625 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
626 x->props.family);
627
David S. Miller8f126e32006-08-24 02:45:07 -0700628 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700629 xfrm_state_hold(x);
630 }
631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (!mod_timer(&x->timer, jiffies + HZ))
633 xfrm_state_hold(x);
634
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800635 if (x->replay_maxage &&
636 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
637 xfrm_state_hold(x);
638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 wake_up(&km_waitq);
640}
641
642void xfrm_state_insert(struct xfrm_state *x)
643{
644 spin_lock_bh(&xfrm_state_lock);
645 __xfrm_state_insert(x);
646 spin_unlock_bh(&xfrm_state_lock);
David S. Miller399c1802005-12-19 14:23:23 -0800647
648 xfrm_flush_all_bundles();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650EXPORT_SYMBOL(xfrm_state_insert);
651
David S. Miller27708342006-08-24 00:13:10 -0700652/* xfrm_state_lock is held */
653static 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)
654{
655 unsigned int h = xfrm_dst_hash(daddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700656 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700657 struct xfrm_state *x;
658
David S. Miller8f126e32006-08-24 02:45:07 -0700659 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700660 if (x->props.reqid != reqid ||
661 x->props.mode != mode ||
662 x->props.family != family ||
663 x->km.state != XFRM_STATE_ACQ ||
664 x->id.spi != 0)
665 continue;
666
667 switch (family) {
668 case AF_INET:
669 if (x->id.daddr.a4 != daddr->a4 ||
670 x->props.saddr.a4 != saddr->a4)
671 continue;
672 break;
673 case AF_INET6:
674 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
675 (struct in6_addr *)daddr) ||
676 !ipv6_addr_equal((struct in6_addr *)
677 x->props.saddr.a6,
678 (struct in6_addr *)saddr))
679 continue;
680 break;
681 };
682
683 xfrm_state_hold(x);
684 return x;
685 }
686
687 if (!create)
688 return NULL;
689
690 x = xfrm_state_alloc();
691 if (likely(x)) {
692 switch (family) {
693 case AF_INET:
694 x->sel.daddr.a4 = daddr->a4;
695 x->sel.saddr.a4 = saddr->a4;
696 x->sel.prefixlen_d = 32;
697 x->sel.prefixlen_s = 32;
698 x->props.saddr.a4 = saddr->a4;
699 x->id.daddr.a4 = daddr->a4;
700 break;
701
702 case AF_INET6:
703 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
704 (struct in6_addr *)daddr);
705 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
706 (struct in6_addr *)saddr);
707 x->sel.prefixlen_d = 128;
708 x->sel.prefixlen_s = 128;
709 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
710 (struct in6_addr *)saddr);
711 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
712 (struct in6_addr *)daddr);
713 break;
714 };
715
716 x->km.state = XFRM_STATE_ACQ;
717 x->id.proto = proto;
718 x->props.family = family;
719 x->props.mode = mode;
720 x->props.reqid = reqid;
721 x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
722 xfrm_state_hold(x);
723 x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
724 add_timer(&x->timer);
725 xfrm_state_hold(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700726 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
David S. Miller27708342006-08-24 00:13:10 -0700727 h = xfrm_src_hash(saddr, family);
728 xfrm_state_hold(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700729 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
David S. Miller27708342006-08-24 00:13:10 -0700730 wake_up(&km_waitq);
731 }
732
733 return x;
734}
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
737
738int xfrm_state_add(struct xfrm_state *x)
739{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 struct xfrm_state *x1;
741 int family;
742 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700743 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 spin_lock_bh(&xfrm_state_lock);
748
David S. Milleredcd5822006-08-24 00:42:45 -0700749 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (x1) {
751 xfrm_state_put(x1);
752 x1 = NULL;
753 err = -EEXIST;
754 goto out;
755 }
756
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700757 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 x1 = __xfrm_find_acq_byseq(x->km.seq);
759 if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) {
760 xfrm_state_put(x1);
761 x1 = NULL;
762 }
763 }
764
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700765 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -0700766 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
767 x->id.proto,
768 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 __xfrm_state_insert(x);
771 err = 0;
772
773out:
774 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
David S. Miller399c1802005-12-19 14:23:23 -0800776 if (!err)
777 xfrm_flush_all_bundles();
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (x1) {
780 xfrm_state_delete(x1);
781 xfrm_state_put(x1);
782 }
783
784 return err;
785}
786EXPORT_SYMBOL(xfrm_state_add);
787
788int xfrm_state_update(struct xfrm_state *x)
789{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 struct xfrm_state *x1;
791 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700792 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -0700795 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 err = -ESRCH;
798 if (!x1)
799 goto out;
800
801 if (xfrm_state_kern(x1)) {
802 xfrm_state_put(x1);
803 err = -EEXIST;
804 goto out;
805 }
806
807 if (x1->km.state == XFRM_STATE_ACQ) {
808 __xfrm_state_insert(x);
809 x = NULL;
810 }
811 err = 0;
812
813out:
814 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 if (err)
817 return err;
818
819 if (!x) {
820 xfrm_state_delete(x1);
821 xfrm_state_put(x1);
822 return 0;
823 }
824
825 err = -EINVAL;
826 spin_lock_bh(&x1->lock);
827 if (likely(x1->km.state == XFRM_STATE_VALID)) {
828 if (x->encap && x1->encap)
829 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700830 if (x->coaddr && x1->coaddr) {
831 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
832 }
833 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
834 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
836 x1->km.dying = 0;
837
838 if (!mod_timer(&x1->timer, jiffies + HZ))
839 xfrm_state_hold(x1);
840 if (x1->curlft.use_time)
841 xfrm_state_check_expire(x1);
842
843 err = 0;
844 }
845 spin_unlock_bh(&x1->lock);
846
847 xfrm_state_put(x1);
848
849 return err;
850}
851EXPORT_SYMBOL(xfrm_state_update);
852
853int xfrm_state_check_expire(struct xfrm_state *x)
854{
855 if (!x->curlft.use_time)
856 x->curlft.use_time = (unsigned long)xtime.tv_sec;
857
858 if (x->km.state != XFRM_STATE_VALID)
859 return -EINVAL;
860
861 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
862 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -0700863 x->km.state = XFRM_STATE_EXPIRED;
864 if (!mod_timer(&x->timer, jiffies))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 xfrm_state_hold(x);
866 return -EINVAL;
867 }
868
869 if (!x->km.dying &&
870 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -0700871 x->curlft.packets >= x->lft.soft_packet_limit)) {
872 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800873 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -0700874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return 0;
876}
877EXPORT_SYMBOL(xfrm_state_check_expire);
878
879static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
880{
881 int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev)
882 - skb_headroom(skb);
883
884 if (nhead > 0)
885 return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
886
887 /* Check tail too... */
888 return 0;
889}
890
891int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
892{
893 int err = xfrm_state_check_expire(x);
894 if (err < 0)
895 goto err;
896 err = xfrm_state_check_space(x, skb);
897err:
898 return err;
899}
900EXPORT_SYMBOL(xfrm_state_check);
901
902struct xfrm_state *
903xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
904 unsigned short family)
905{
906 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -0700909 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 return x;
912}
913EXPORT_SYMBOL(xfrm_state_lookup);
914
915struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700916xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
917 u8 proto, unsigned short family)
918{
919 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700920
921 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -0700922 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700923 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700924 return x;
925}
926EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
927
928struct xfrm_state *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
930 xfrm_address_t *daddr, xfrm_address_t *saddr,
931 int create, unsigned short family)
932{
933 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -0700936 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -0700938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 return x;
940}
941EXPORT_SYMBOL(xfrm_find_acq);
942
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -0700943#ifdef CONFIG_XFRM_SUB_POLICY
944int
945xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
946 unsigned short family)
947{
948 int err = 0;
949 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
950 if (!afinfo)
951 return -EAFNOSUPPORT;
952
953 spin_lock_bh(&xfrm_state_lock);
954 if (afinfo->tmpl_sort)
955 err = afinfo->tmpl_sort(dst, src, n);
956 spin_unlock_bh(&xfrm_state_lock);
957 xfrm_state_put_afinfo(afinfo);
958 return err;
959}
960EXPORT_SYMBOL(xfrm_tmpl_sort);
961
962int
963xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
964 unsigned short family)
965{
966 int err = 0;
967 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
968 if (!afinfo)
969 return -EAFNOSUPPORT;
970
971 spin_lock_bh(&xfrm_state_lock);
972 if (afinfo->state_sort)
973 err = afinfo->state_sort(dst, src, n);
974 spin_unlock_bh(&xfrm_state_lock);
975 xfrm_state_put_afinfo(afinfo);
976 return err;
977}
978EXPORT_SYMBOL(xfrm_state_sort);
979#endif
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981/* Silly enough, but I'm lazy to build resolution list */
982
983static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
984{
985 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 for (i = 0; i < XFRM_DST_HSIZE; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700988 struct hlist_node *entry;
989 struct xfrm_state *x;
990
991 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
992 if (x->km.seq == seq &&
993 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 xfrm_state_hold(x);
995 return x;
996 }
997 }
998 }
999 return NULL;
1000}
1001
1002struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1003{
1004 struct xfrm_state *x;
1005
1006 spin_lock_bh(&xfrm_state_lock);
1007 x = __xfrm_find_acq_byseq(seq);
1008 spin_unlock_bh(&xfrm_state_lock);
1009 return x;
1010}
1011EXPORT_SYMBOL(xfrm_find_acq_byseq);
1012
1013u32 xfrm_get_acqseq(void)
1014{
1015 u32 res;
1016 static u32 acqseq;
1017 static DEFINE_SPINLOCK(acqseq_lock);
1018
1019 spin_lock_bh(&acqseq_lock);
1020 res = (++acqseq ? : ++acqseq);
1021 spin_unlock_bh(&acqseq_lock);
1022 return res;
1023}
1024EXPORT_SYMBOL(xfrm_get_acqseq);
1025
1026void
1027xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
1028{
1029 u32 h;
1030 struct xfrm_state *x0;
1031
1032 if (x->id.spi)
1033 return;
1034
1035 if (minspi == maxspi) {
1036 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1037 if (x0) {
1038 xfrm_state_put(x0);
1039 return;
1040 }
1041 x->id.spi = minspi;
1042 } else {
1043 u32 spi = 0;
1044 minspi = ntohl(minspi);
1045 maxspi = ntohl(maxspi);
1046 for (h=0; h<maxspi-minspi+1; h++) {
1047 spi = minspi + net_random()%(maxspi-minspi+1);
1048 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1049 if (x0 == NULL) {
1050 x->id.spi = htonl(spi);
1051 break;
1052 }
1053 xfrm_state_put(x0);
1054 }
1055 }
1056 if (x->id.spi) {
1057 spin_lock_bh(&xfrm_state_lock);
1058 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -07001059 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 xfrm_state_hold(x);
1061 spin_unlock_bh(&xfrm_state_lock);
1062 wake_up(&km_waitq);
1063 }
1064}
1065EXPORT_SYMBOL(xfrm_alloc_spi);
1066
1067int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
1068 void *data)
1069{
1070 int i;
1071 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -07001072 struct hlist_node *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 int count = 0;
1074 int err = 0;
1075
1076 spin_lock_bh(&xfrm_state_lock);
1077 for (i = 0; i < XFRM_DST_HSIZE; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001078 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
Masahide NAKAMURA57947082006-09-22 15:06:24 -07001079 if (xfrm_id_proto_match(x->id.proto, proto))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 count++;
1081 }
1082 }
1083 if (count == 0) {
1084 err = -ENOENT;
1085 goto out;
1086 }
1087
1088 for (i = 0; i < XFRM_DST_HSIZE; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001089 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
Masahide NAKAMURA57947082006-09-22 15:06:24 -07001090 if (!xfrm_id_proto_match(x->id.proto, proto))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 continue;
1092 err = func(x, --count, data);
1093 if (err)
1094 goto out;
1095 }
1096 }
1097out:
1098 spin_unlock_bh(&xfrm_state_lock);
1099 return err;
1100}
1101EXPORT_SYMBOL(xfrm_state_walk);
1102
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001103
1104void xfrm_replay_notify(struct xfrm_state *x, int event)
1105{
1106 struct km_event c;
1107 /* we send notify messages in case
1108 * 1. we updated on of the sequence numbers, and the seqno difference
1109 * is at least x->replay_maxdiff, in this case we also update the
1110 * timeout of our timer function
1111 * 2. if x->replay_maxage has elapsed since last update,
1112 * and there were changes
1113 *
1114 * The state structure must be locked!
1115 */
1116
1117 switch (event) {
1118 case XFRM_REPLAY_UPDATE:
1119 if (x->replay_maxdiff &&
1120 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001121 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1122 if (x->xflags & XFRM_TIME_DEFER)
1123 event = XFRM_REPLAY_TIMEOUT;
1124 else
1125 return;
1126 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001127
1128 break;
1129
1130 case XFRM_REPLAY_TIMEOUT:
1131 if ((x->replay.seq == x->preplay.seq) &&
1132 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001133 (x->replay.oseq == x->preplay.oseq)) {
1134 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001135 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001136 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001137
1138 break;
1139 }
1140
1141 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1142 c.event = XFRM_MSG_NEWAE;
1143 c.data.aevent = event;
1144 km_state_notify(x, &c);
1145
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001146 if (x->replay_maxage &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001147 !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) {
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001148 xfrm_state_hold(x);
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001149 x->xflags &= ~XFRM_TIME_DEFER;
1150 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001151}
David S. Millera70fcb02006-03-20 19:18:52 -08001152EXPORT_SYMBOL(xfrm_replay_notify);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001153
1154static void xfrm_replay_timer_handler(unsigned long data)
1155{
1156 struct xfrm_state *x = (struct xfrm_state*)data;
1157
1158 spin_lock(&x->lock);
1159
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001160 if (x->km.state == XFRM_STATE_VALID) {
1161 if (xfrm_aevent_is_on())
1162 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1163 else
1164 x->xflags |= XFRM_TIME_DEFER;
1165 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001166
1167 spin_unlock(&x->lock);
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001168 xfrm_state_put(x);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001169}
1170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171int xfrm_replay_check(struct xfrm_state *x, u32 seq)
1172{
1173 u32 diff;
1174
1175 seq = ntohl(seq);
1176
1177 if (unlikely(seq == 0))
1178 return -EINVAL;
1179
1180 if (likely(seq > x->replay.seq))
1181 return 0;
1182
1183 diff = x->replay.seq - seq;
1184 if (diff >= x->props.replay_window) {
1185 x->stats.replay_window++;
1186 return -EINVAL;
1187 }
1188
1189 if (x->replay.bitmap & (1U << diff)) {
1190 x->stats.replay++;
1191 return -EINVAL;
1192 }
1193 return 0;
1194}
1195EXPORT_SYMBOL(xfrm_replay_check);
1196
1197void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
1198{
1199 u32 diff;
1200
1201 seq = ntohl(seq);
1202
1203 if (seq > x->replay.seq) {
1204 diff = seq - x->replay.seq;
1205 if (diff < x->props.replay_window)
1206 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1207 else
1208 x->replay.bitmap = 1;
1209 x->replay.seq = seq;
1210 } else {
1211 diff = x->replay.seq - seq;
1212 x->replay.bitmap |= (1U << diff);
1213 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001214
1215 if (xfrm_aevent_is_on())
1216 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217}
1218EXPORT_SYMBOL(xfrm_replay_advance);
1219
1220static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
1221static DEFINE_RWLOCK(xfrm_km_lock);
1222
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001223void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
1225 struct xfrm_mgr *km;
1226
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001227 read_lock(&xfrm_km_lock);
1228 list_for_each_entry(km, &xfrm_km_list, list)
1229 if (km->notify_policy)
1230 km->notify_policy(xp, dir, c);
1231 read_unlock(&xfrm_km_lock);
1232}
1233
1234void km_state_notify(struct xfrm_state *x, struct km_event *c)
1235{
1236 struct xfrm_mgr *km;
1237 read_lock(&xfrm_km_lock);
1238 list_for_each_entry(km, &xfrm_km_list, list)
1239 if (km->notify)
1240 km->notify(x, c);
1241 read_unlock(&xfrm_km_lock);
1242}
1243
1244EXPORT_SYMBOL(km_policy_notify);
1245EXPORT_SYMBOL(km_state_notify);
1246
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001247void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001248{
1249 struct km_event c;
1250
Herbert Xubf088672005-06-18 22:44:00 -07001251 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001252 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001253 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001254 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 if (hard)
1257 wake_up(&km_waitq);
1258}
1259
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001260EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001261/*
1262 * We send to all registered managers regardless of failure
1263 * We are happy with one success
1264*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001265int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001267 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 struct xfrm_mgr *km;
1269
1270 read_lock(&xfrm_km_lock);
1271 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001272 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1273 if (!acqret)
1274 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 }
1276 read_unlock(&xfrm_km_lock);
1277 return err;
1278}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001279EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
1282{
1283 int err = -EINVAL;
1284 struct xfrm_mgr *km;
1285
1286 read_lock(&xfrm_km_lock);
1287 list_for_each_entry(km, &xfrm_km_list, list) {
1288 if (km->new_mapping)
1289 err = km->new_mapping(x, ipaddr, sport);
1290 if (!err)
1291 break;
1292 }
1293 read_unlock(&xfrm_km_lock);
1294 return err;
1295}
1296EXPORT_SYMBOL(km_new_mapping);
1297
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001298void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001300 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Herbert Xubf088672005-06-18 22:44:00 -07001302 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001303 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001304 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001305 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
1307 if (hard)
1308 wake_up(&km_waitq);
1309}
David S. Millera70fcb02006-03-20 19:18:52 -08001310EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001312int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1313{
1314 int err = -EINVAL;
1315 int ret;
1316 struct xfrm_mgr *km;
1317
1318 read_lock(&xfrm_km_lock);
1319 list_for_each_entry(km, &xfrm_km_list, list) {
1320 if (km->report) {
1321 ret = km->report(proto, sel, addr);
1322 if (!ret)
1323 err = ret;
1324 }
1325 }
1326 read_unlock(&xfrm_km_lock);
1327 return err;
1328}
1329EXPORT_SYMBOL(km_report);
1330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1332{
1333 int err;
1334 u8 *data;
1335 struct xfrm_mgr *km;
1336 struct xfrm_policy *pol = NULL;
1337
1338 if (optlen <= 0 || optlen > PAGE_SIZE)
1339 return -EMSGSIZE;
1340
1341 data = kmalloc(optlen, GFP_KERNEL);
1342 if (!data)
1343 return -ENOMEM;
1344
1345 err = -EFAULT;
1346 if (copy_from_user(data, optval, optlen))
1347 goto out;
1348
1349 err = -EINVAL;
1350 read_lock(&xfrm_km_lock);
1351 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001352 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 optlen, &err);
1354 if (err >= 0)
1355 break;
1356 }
1357 read_unlock(&xfrm_km_lock);
1358
1359 if (err >= 0) {
1360 xfrm_sk_policy_insert(sk, err, pol);
1361 xfrm_pol_put(pol);
1362 err = 0;
1363 }
1364
1365out:
1366 kfree(data);
1367 return err;
1368}
1369EXPORT_SYMBOL(xfrm_user_policy);
1370
1371int xfrm_register_km(struct xfrm_mgr *km)
1372{
1373 write_lock_bh(&xfrm_km_lock);
1374 list_add_tail(&km->list, &xfrm_km_list);
1375 write_unlock_bh(&xfrm_km_lock);
1376 return 0;
1377}
1378EXPORT_SYMBOL(xfrm_register_km);
1379
1380int xfrm_unregister_km(struct xfrm_mgr *km)
1381{
1382 write_lock_bh(&xfrm_km_lock);
1383 list_del(&km->list);
1384 write_unlock_bh(&xfrm_km_lock);
1385 return 0;
1386}
1387EXPORT_SYMBOL(xfrm_unregister_km);
1388
1389int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1390{
1391 int err = 0;
1392 if (unlikely(afinfo == NULL))
1393 return -EINVAL;
1394 if (unlikely(afinfo->family >= NPROTO))
1395 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001396 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1398 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001399 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001401 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 return err;
1403}
1404EXPORT_SYMBOL(xfrm_state_register_afinfo);
1405
1406int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1407{
1408 int err = 0;
1409 if (unlikely(afinfo == NULL))
1410 return -EINVAL;
1411 if (unlikely(afinfo->family >= NPROTO))
1412 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001413 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1415 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1416 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001417 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001420 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 return err;
1422}
1423EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1424
1425static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
1426{
1427 struct xfrm_state_afinfo *afinfo;
1428 if (unlikely(family >= NPROTO))
1429 return NULL;
1430 read_lock(&xfrm_state_afinfo_lock);
1431 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001432 if (unlikely(!afinfo))
1433 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 return afinfo;
1435}
1436
1437static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
1438{
Herbert Xu546be242006-05-27 23:03:58 -07001439 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440}
1441
1442/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1443void xfrm_state_delete_tunnel(struct xfrm_state *x)
1444{
1445 if (x->tunnel) {
1446 struct xfrm_state *t = x->tunnel;
1447
1448 if (atomic_read(&t->tunnel_users) == 2)
1449 xfrm_state_delete(t);
1450 atomic_dec(&t->tunnel_users);
1451 xfrm_state_put(t);
1452 x->tunnel = NULL;
1453 }
1454}
1455EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1456
Herbert Xu80b30c12005-10-15 10:58:30 +10001457/*
1458 * This function is NOT optimal. For example, with ESP it will give an
1459 * MTU that's usually two bytes short of being optimal. However, it will
1460 * usually give an answer that's a multiple of 4 provided the input is
1461 * also a multiple of 4.
1462 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1464{
1465 int res = mtu;
1466
1467 res -= x->props.header_len;
1468
1469 for (;;) {
1470 int m = res;
1471
1472 if (m < 68)
1473 return 68;
1474
1475 spin_lock_bh(&x->lock);
1476 if (x->km.state == XFRM_STATE_VALID &&
1477 x->type && x->type->get_max_size)
1478 m = x->type->get_max_size(x, m);
1479 else
1480 m += x->props.header_len;
1481 spin_unlock_bh(&x->lock);
1482
1483 if (m <= mtu)
1484 break;
1485 res -= (m - mtu);
1486 }
1487
1488 return res;
1489}
1490
Herbert Xu72cb6962005-06-20 13:18:08 -07001491int xfrm_init_state(struct xfrm_state *x)
1492{
Herbert Xud094cd82005-06-20 13:19:41 -07001493 struct xfrm_state_afinfo *afinfo;
1494 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001495 int err;
1496
Herbert Xud094cd82005-06-20 13:19:41 -07001497 err = -EAFNOSUPPORT;
1498 afinfo = xfrm_state_get_afinfo(family);
1499 if (!afinfo)
1500 goto error;
1501
1502 err = 0;
1503 if (afinfo->init_flags)
1504 err = afinfo->init_flags(x);
1505
1506 xfrm_state_put_afinfo(afinfo);
1507
1508 if (err)
1509 goto error;
1510
1511 err = -EPROTONOSUPPORT;
1512 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07001513 if (x->type == NULL)
1514 goto error;
1515
1516 err = x->type->init_state(x);
1517 if (err)
1518 goto error;
1519
Herbert Xub59f45d2006-05-27 23:05:54 -07001520 x->mode = xfrm_get_mode(x->props.mode, family);
1521 if (x->mode == NULL)
1522 goto error;
1523
Herbert Xu72cb6962005-06-20 13:18:08 -07001524 x->km.state = XFRM_STATE_VALID;
1525
1526error:
1527 return err;
1528}
1529
1530EXPORT_SYMBOL(xfrm_init_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532void __init xfrm_state_init(void)
1533{
1534 int i;
1535
1536 for (i=0; i<XFRM_DST_HSIZE; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001537 INIT_HLIST_HEAD(&xfrm_state_bydst[i]);
1538 INIT_HLIST_HEAD(&xfrm_state_bysrc[i]);
1539 INIT_HLIST_HEAD(&xfrm_state_byspi[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 }
1541 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
1542}
1543