blob: 053970e8765db78faef80d6032f1d96fc698ae09 [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>
David S. Millerf034b5d2006-08-24 03:08:07 -070021#include <linux/cache.h>
Paul Moore68277ac2007-12-20 20:49:33 -080022#include <linux/audit.h>
Jesper Juhlb5890d82007-08-10 15:20:21 -070023#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
David S. Miller44e36b42006-08-24 04:50:50 -070025#include "xfrm_hash.h"
26
David S. Milleree857a72006-03-20 19:18:37 -080027struct sock *xfrm_nl;
28EXPORT_SYMBOL(xfrm_nl);
29
David S. Miller01e67d02007-05-25 00:41:38 -070030u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME;
David S. Millera70fcb02006-03-20 19:18:52 -080031EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
32
David S. Miller01e67d02007-05-25 00:41:38 -070033u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE;
David S. Millera70fcb02006-03-20 19:18:52 -080034EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
35
David S. Miller01e67d02007-05-25 00:41:38 -070036u32 sysctl_xfrm_acq_expires __read_mostly = 30;
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/* Each xfrm_state may be linked to two tables:
39
40 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
David S. Millera624c102006-08-24 03:24:33 -070041 2. Hash table by (daddr,family,reqid) to find what SAs exist for given
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 destination/tunnel endpoint. (output)
43 */
44
45static DEFINE_SPINLOCK(xfrm_state_lock);
46
47/* Hash table to find appropriate SA towards given target (endpoint
48 * of tunnel or destination of transport mode) allowed by selector.
49 *
50 * Main use is finding SA after policy selected tunnel or transport mode.
51 * Also, it can be used by ah/esp icmp error handler to find offending SA.
52 */
Timo Teras4c563f72008-02-28 21:31:08 -080053static LIST_HEAD(xfrm_state_all);
David S. Millerf034b5d2006-08-24 03:08:07 -070054static struct hlist_head *xfrm_state_bydst __read_mostly;
55static struct hlist_head *xfrm_state_bysrc __read_mostly;
56static struct hlist_head *xfrm_state_byspi __read_mostly;
57static unsigned int xfrm_state_hmask __read_mostly;
58static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
59static unsigned int xfrm_state_num;
David S. Miller9d4a7062006-08-24 03:18:09 -070060static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Herbert Xuabb81c42008-09-09 19:58:29 -070062/* Counter indicating ongoing walk, protected by xfrm_state_lock. */
63static unsigned long xfrm_state_walk_ongoing;
64/* Counter indicating walk completion, protected by xfrm_cfg_mutex. */
65static unsigned long xfrm_state_walk_completed;
66
Herbert Xu5c182452008-09-22 19:48:19 -070067/* List of outstanding state walks used to set the completed counter. */
68static LIST_HEAD(xfrm_state_walks);
69
Herbert Xu17c2a422007-10-17 21:33:12 -070070static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
71static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
72
Paul Mooreafeb14b2007-12-21 14:58:11 -080073#ifdef CONFIG_AUDITSYSCALL
74static void xfrm_audit_state_replay(struct xfrm_state *x,
75 struct sk_buff *skb, __be32 net_seq);
76#else
77#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
78#endif /* CONFIG_AUDITSYSCALL */
79
David S. Millerc1969f22006-08-24 04:00:03 -070080static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
81 xfrm_address_t *saddr,
82 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070083 unsigned short family)
84{
David S. Millerc1969f22006-08-24 04:00:03 -070085 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070086}
87
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070088static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
89 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070090 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070091{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070092 return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070093}
94
David S. Miller2575b652006-08-24 03:26:44 -070095static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070096xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070097{
David S. Millerc1969f22006-08-24 04:00:03 -070098 return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070099}
100
David S. Millerf034b5d2006-08-24 03:08:07 -0700101static void xfrm_hash_transfer(struct hlist_head *list,
102 struct hlist_head *ndsttable,
103 struct hlist_head *nsrctable,
104 struct hlist_head *nspitable,
105 unsigned int nhashmask)
106{
107 struct hlist_node *entry, *tmp;
108 struct xfrm_state *x;
109
110 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
111 unsigned int h;
112
David S. Millerc1969f22006-08-24 04:00:03 -0700113 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
114 x->props.reqid, x->props.family,
115 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -0700116 hlist_add_head(&x->bydst, ndsttable+h);
117
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700118 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
119 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700120 nhashmask);
121 hlist_add_head(&x->bysrc, nsrctable+h);
122
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700123 if (x->id.spi) {
124 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
125 x->id.proto, x->props.family,
126 nhashmask);
127 hlist_add_head(&x->byspi, nspitable+h);
128 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700129 }
130}
131
132static unsigned long xfrm_hash_new_size(void)
133{
134 return ((xfrm_state_hmask + 1) << 1) *
135 sizeof(struct hlist_head);
136}
137
138static DEFINE_MUTEX(hash_resize_mutex);
139
David Howellsc4028952006-11-22 14:57:56 +0000140static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700141{
142 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
143 unsigned long nsize, osize;
144 unsigned int nhashmask, ohashmask;
145 int i;
146
147 mutex_lock(&hash_resize_mutex);
148
149 nsize = xfrm_hash_new_size();
David S. Miller44e36b42006-08-24 04:50:50 -0700150 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700151 if (!ndst)
152 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700153 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700154 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700155 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700156 goto out_unlock;
157 }
David S. Miller44e36b42006-08-24 04:50:50 -0700158 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700159 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700160 xfrm_hash_free(ndst, nsize);
161 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700162 goto out_unlock;
163 }
164
165 spin_lock_bh(&xfrm_state_lock);
166
167 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
168 for (i = xfrm_state_hmask; i >= 0; i--)
169 xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,
170 nhashmask);
171
172 odst = xfrm_state_bydst;
173 osrc = xfrm_state_bysrc;
174 ospi = xfrm_state_byspi;
175 ohashmask = xfrm_state_hmask;
176
177 xfrm_state_bydst = ndst;
178 xfrm_state_bysrc = nsrc;
179 xfrm_state_byspi = nspi;
180 xfrm_state_hmask = nhashmask;
181
182 spin_unlock_bh(&xfrm_state_lock);
183
184 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700185 xfrm_hash_free(odst, osize);
186 xfrm_hash_free(osrc, osize);
187 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700188
189out_unlock:
190 mutex_unlock(&hash_resize_mutex);
191}
192
David Howellsc4028952006-11-22 14:57:56 +0000193static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195DECLARE_WAIT_QUEUE_HEAD(km_waitq);
196EXPORT_SYMBOL(km_waitq);
197
198static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
199static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
200
201static struct work_struct xfrm_state_gc_work;
Herbert Xuabb81c42008-09-09 19:58:29 -0700202static LIST_HEAD(xfrm_state_gc_leftovers);
203static LIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static DEFINE_SPINLOCK(xfrm_state_gc_lock);
205
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800206int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800208int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800209void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700211static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
212{
213 struct xfrm_state_afinfo *afinfo;
214 if (unlikely(family >= NPROTO))
215 return NULL;
216 write_lock_bh(&xfrm_state_afinfo_lock);
217 afinfo = xfrm_state_afinfo[family];
218 if (unlikely(!afinfo))
219 write_unlock_bh(&xfrm_state_afinfo_lock);
220 return afinfo;
221}
222
223static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800224 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700225{
226 write_unlock_bh(&xfrm_state_afinfo_lock);
227}
228
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800229int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700230{
231 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800232 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700233 int err = 0;
234
235 if (unlikely(afinfo == NULL))
236 return -EAFNOSUPPORT;
237 typemap = afinfo->type_map;
238
239 if (likely(typemap[type->proto] == NULL))
240 typemap[type->proto] = type;
241 else
242 err = -EEXIST;
243 xfrm_state_unlock_afinfo(afinfo);
244 return err;
245}
246EXPORT_SYMBOL(xfrm_register_type);
247
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800248int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700249{
250 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800251 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700252 int err = 0;
253
254 if (unlikely(afinfo == NULL))
255 return -EAFNOSUPPORT;
256 typemap = afinfo->type_map;
257
258 if (unlikely(typemap[type->proto] != type))
259 err = -ENOENT;
260 else
261 typemap[type->proto] = NULL;
262 xfrm_state_unlock_afinfo(afinfo);
263 return err;
264}
265EXPORT_SYMBOL(xfrm_unregister_type);
266
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800267static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700268{
269 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800270 const struct xfrm_type **typemap;
271 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700272 int modload_attempted = 0;
273
274retry:
275 afinfo = xfrm_state_get_afinfo(family);
276 if (unlikely(afinfo == NULL))
277 return NULL;
278 typemap = afinfo->type_map;
279
280 type = typemap[proto];
281 if (unlikely(type && !try_module_get(type->owner)))
282 type = NULL;
283 if (!type && !modload_attempted) {
284 xfrm_state_put_afinfo(afinfo);
285 request_module("xfrm-type-%d-%d", family, proto);
286 modload_attempted = 1;
287 goto retry;
288 }
289
290 xfrm_state_put_afinfo(afinfo);
291 return type;
292}
293
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800294static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700295{
296 module_put(type->owner);
297}
298
299int xfrm_register_mode(struct xfrm_mode *mode, int family)
300{
301 struct xfrm_state_afinfo *afinfo;
302 struct xfrm_mode **modemap;
303 int err;
304
305 if (unlikely(mode->encap >= XFRM_MODE_MAX))
306 return -EINVAL;
307
308 afinfo = xfrm_state_lock_afinfo(family);
309 if (unlikely(afinfo == NULL))
310 return -EAFNOSUPPORT;
311
312 err = -EEXIST;
313 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700314 if (modemap[mode->encap])
315 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700316
Herbert Xu17c2a422007-10-17 21:33:12 -0700317 err = -ENOENT;
318 if (!try_module_get(afinfo->owner))
319 goto out;
320
321 mode->afinfo = afinfo;
322 modemap[mode->encap] = mode;
323 err = 0;
324
325out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700326 xfrm_state_unlock_afinfo(afinfo);
327 return err;
328}
329EXPORT_SYMBOL(xfrm_register_mode);
330
331int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
332{
333 struct xfrm_state_afinfo *afinfo;
334 struct xfrm_mode **modemap;
335 int err;
336
337 if (unlikely(mode->encap >= XFRM_MODE_MAX))
338 return -EINVAL;
339
340 afinfo = xfrm_state_lock_afinfo(family);
341 if (unlikely(afinfo == NULL))
342 return -EAFNOSUPPORT;
343
344 err = -ENOENT;
345 modemap = afinfo->mode_map;
346 if (likely(modemap[mode->encap] == mode)) {
347 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700348 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700349 err = 0;
350 }
351
352 xfrm_state_unlock_afinfo(afinfo);
353 return err;
354}
355EXPORT_SYMBOL(xfrm_unregister_mode);
356
357static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
358{
359 struct xfrm_state_afinfo *afinfo;
360 struct xfrm_mode *mode;
361 int modload_attempted = 0;
362
363 if (unlikely(encap >= XFRM_MODE_MAX))
364 return NULL;
365
366retry:
367 afinfo = xfrm_state_get_afinfo(family);
368 if (unlikely(afinfo == NULL))
369 return NULL;
370
371 mode = afinfo->mode_map[encap];
372 if (unlikely(mode && !try_module_get(mode->owner)))
373 mode = NULL;
374 if (!mode && !modload_attempted) {
375 xfrm_state_put_afinfo(afinfo);
376 request_module("xfrm-mode-%d-%d", family, encap);
377 modload_attempted = 1;
378 goto retry;
379 }
380
381 xfrm_state_put_afinfo(afinfo);
382 return mode;
383}
384
385static void xfrm_put_mode(struct xfrm_mode *mode)
386{
387 module_put(mode->owner);
388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390static void xfrm_state_gc_destroy(struct xfrm_state *x)
391{
David S. Millera47f0ce2006-08-24 03:54:22 -0700392 del_timer_sync(&x->timer);
393 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800394 kfree(x->aalg);
395 kfree(x->ealg);
396 kfree(x->calg);
397 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700398 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700399 if (x->inner_mode)
400 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700401 if (x->inner_mode_iaf)
402 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700403 if (x->outer_mode)
404 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (x->type) {
406 x->type->destructor(x);
407 xfrm_put_type(x->type);
408 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800409 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 kfree(x);
411}
412
David Howellsc4028952006-11-22 14:57:56 +0000413static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
Herbert Xuabb81c42008-09-09 19:58:29 -0700415 struct xfrm_state *x, *tmp;
416 unsigned long completed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Herbert Xuabb81c42008-09-09 19:58:29 -0700418 mutex_lock(&xfrm_cfg_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -0700420 list_splice_tail_init(&xfrm_state_gc_list, &xfrm_state_gc_leftovers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 spin_unlock_bh(&xfrm_state_gc_lock);
422
Herbert Xuabb81c42008-09-09 19:58:29 -0700423 completed = xfrm_state_walk_completed;
424 mutex_unlock(&xfrm_cfg_mutex);
425
426 list_for_each_entry_safe(x, tmp, &xfrm_state_gc_leftovers, gclist) {
427 if ((long)(x->lastused - completed) > 0)
428 break;
David S. Miller08569902008-09-09 22:13:28 -0700429 list_del(&x->gclist);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 xfrm_state_gc_destroy(x);
Herbert Xuabb81c42008-09-09 19:58:29 -0700431 }
David S. Miller8f126e32006-08-24 02:45:07 -0700432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 wake_up(&km_waitq);
434}
435
436static inline unsigned long make_jiffies(long secs)
437{
438 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
439 return MAX_SCHEDULE_TIMEOUT-1;
440 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900441 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
444static void xfrm_timer_handler(unsigned long data)
445{
446 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800447 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 long next = LONG_MAX;
449 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600450 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452 spin_lock(&x->lock);
453 if (x->km.state == XFRM_STATE_DEAD)
454 goto out;
455 if (x->km.state == XFRM_STATE_EXPIRED)
456 goto expired;
457 if (x->lft.hard_add_expires_seconds) {
458 long tmo = x->lft.hard_add_expires_seconds +
459 x->curlft.add_time - now;
460 if (tmo <= 0)
461 goto expired;
462 if (tmo < next)
463 next = tmo;
464 }
465 if (x->lft.hard_use_expires_seconds) {
466 long tmo = x->lft.hard_use_expires_seconds +
467 (x->curlft.use_time ? : now) - now;
468 if (tmo <= 0)
469 goto expired;
470 if (tmo < next)
471 next = tmo;
472 }
473 if (x->km.dying)
474 goto resched;
475 if (x->lft.soft_add_expires_seconds) {
476 long tmo = x->lft.soft_add_expires_seconds +
477 x->curlft.add_time - now;
478 if (tmo <= 0)
479 warn = 1;
480 else if (tmo < next)
481 next = tmo;
482 }
483 if (x->lft.soft_use_expires_seconds) {
484 long tmo = x->lft.soft_use_expires_seconds +
485 (x->curlft.use_time ? : now) - now;
486 if (tmo <= 0)
487 warn = 1;
488 else if (tmo < next)
489 next = tmo;
490 }
491
Herbert Xu4666faa2005-06-18 22:43:22 -0700492 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800494 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700496 if (next != LONG_MAX)
497 mod_timer(&x->timer, jiffies + make_jiffies(next));
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 goto out;
500
501expired:
502 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
503 x->km.state = XFRM_STATE_EXPIRED;
504 wake_up(&km_waitq);
505 next = 2;
506 goto resched;
507 }
Joy Latten161a09e2006-11-27 13:11:54 -0600508
509 err = __xfrm_state_delete(x);
510 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800511 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Joy Lattenab5f5e82007-09-17 11:51:22 -0700513 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400514 audit_get_loginuid(current),
515 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517out:
518 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519}
520
David S. Miller0ac84752006-03-20 19:18:23 -0800521static void xfrm_replay_timer_handler(unsigned long data);
522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523struct xfrm_state *xfrm_state_alloc(void)
524{
525 struct xfrm_state *x;
526
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700527 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
529 if (x) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 atomic_set(&x->refcnt, 1);
531 atomic_set(&x->tunnel_users, 0);
Timo Teras4c563f72008-02-28 21:31:08 -0800532 INIT_LIST_HEAD(&x->all);
David S. Miller8f126e32006-08-24 02:45:07 -0700533 INIT_HLIST_NODE(&x->bydst);
534 INIT_HLIST_NODE(&x->bysrc);
535 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800536 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
537 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
538 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800539 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 x->lft.soft_byte_limit = XFRM_INF;
541 x->lft.soft_packet_limit = XFRM_INF;
542 x->lft.hard_byte_limit = XFRM_INF;
543 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800544 x->replay_maxage = 0;
545 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700546 x->inner_mode = NULL;
547 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 spin_lock_init(&x->lock);
549 }
550 return x;
551}
552EXPORT_SYMBOL(xfrm_state_alloc);
553
554void __xfrm_state_destroy(struct xfrm_state *x)
555{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700556 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -0700559 list_add_tail(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 spin_unlock_bh(&xfrm_state_gc_lock);
561 schedule_work(&xfrm_state_gc_work);
562}
563EXPORT_SYMBOL(__xfrm_state_destroy);
564
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800565int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567 int err = -ESRCH;
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (x->km.state != XFRM_STATE_DEAD) {
570 x->km.state = XFRM_STATE_DEAD;
571 spin_lock(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -0700572 x->lastused = xfrm_state_walk_ongoing;
573 list_del_rcu(&x->all);
David S. Miller8f126e32006-08-24 02:45:07 -0700574 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700575 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700576 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700577 hlist_del(&x->byspi);
David S. Millerf034b5d2006-08-24 03:08:07 -0700578 xfrm_state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 /* All xfrm_state objects are created by xfrm_state_alloc.
582 * The xfrm_state_alloc call gives a reference, and that
583 * is what we are dropping here.
584 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800585 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700586 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700588
589 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800591EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700593int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700595 int err;
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700598 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700600
601 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603EXPORT_SYMBOL(xfrm_state_delete);
604
Joy Latten4aa2e622007-06-04 19:05:57 -0400605#ifdef CONFIG_SECURITY_NETWORK_XFRM
606static inline int
607xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
Joy Latten4aa2e622007-06-04 19:05:57 -0400609 int i, err = 0;
610
611 for (i = 0; i <= xfrm_state_hmask; i++) {
612 struct hlist_node *entry;
613 struct xfrm_state *x;
614
615 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
616 if (xfrm_id_proto_match(x->id.proto, proto) &&
617 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700618 xfrm_audit_state_delete(x, 0,
619 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400620 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700621 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400622 return err;
623 }
624 }
625 }
626
627 return err;
628}
629#else
630static inline int
631xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
632{
633 return 0;
634}
635#endif
636
637int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
638{
639 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400642 err = xfrm_state_flush_secctx_check(proto, audit_info);
643 if (err)
644 goto out;
645
Masahide NAKAMURAa9917c02006-08-31 15:14:32 -0700646 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700647 struct hlist_node *entry;
648 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649restart:
David S. Miller8f126e32006-08-24 02:45:07 -0700650 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700652 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 xfrm_state_hold(x);
654 spin_unlock_bh(&xfrm_state_lock);
655
Joy Latten161a09e2006-11-27 13:11:54 -0600656 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700657 xfrm_audit_state_delete(x, err ? 0 : 1,
658 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400659 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700660 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 xfrm_state_put(x);
662
663 spin_lock_bh(&xfrm_state_lock);
664 goto restart;
665 }
666 }
667 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400668 err = 0;
669
670out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 spin_unlock_bh(&xfrm_state_lock);
672 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400673 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675EXPORT_SYMBOL(xfrm_state_flush);
676
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700677void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700678{
679 spin_lock_bh(&xfrm_state_lock);
680 si->sadcnt = xfrm_state_num;
681 si->sadhcnt = xfrm_state_hmask;
682 si->sadhmcnt = xfrm_state_hashmax;
683 spin_unlock_bh(&xfrm_state_lock);
684}
685EXPORT_SYMBOL(xfrm_sad_getinfo);
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687static int
688xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
689 struct xfrm_tmpl *tmpl,
690 xfrm_address_t *daddr, xfrm_address_t *saddr,
691 unsigned short family)
692{
693 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
694 if (!afinfo)
695 return -1;
696 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
697 xfrm_state_put_afinfo(afinfo);
698 return 0;
699}
700
Al Viroa94cfd12006-09-27 18:47:24 -0700701static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Milleredcd5822006-08-24 00:42:45 -0700702{
703 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
704 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700705 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700706
David S. Miller8f126e32006-08-24 02:45:07 -0700707 hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700708 if (x->props.family != family ||
709 x->id.spi != spi ||
710 x->id.proto != proto)
711 continue;
712
713 switch (family) {
714 case AF_INET:
715 if (x->id.daddr.a4 != daddr->a4)
716 continue;
717 break;
718 case AF_INET6:
719 if (!ipv6_addr_equal((struct in6_addr *)daddr,
720 (struct in6_addr *)
721 x->id.daddr.a6))
722 continue;
723 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700724 }
David S. Milleredcd5822006-08-24 00:42:45 -0700725
726 xfrm_state_hold(x);
727 return x;
728 }
729
730 return NULL;
731}
732
733static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
734{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700735 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700736 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700737 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700738
David S. Miller8f126e32006-08-24 02:45:07 -0700739 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700740 if (x->props.family != family ||
741 x->id.proto != proto)
742 continue;
743
744 switch (family) {
745 case AF_INET:
746 if (x->id.daddr.a4 != daddr->a4 ||
747 x->props.saddr.a4 != saddr->a4)
748 continue;
749 break;
750 case AF_INET6:
751 if (!ipv6_addr_equal((struct in6_addr *)daddr,
752 (struct in6_addr *)
753 x->id.daddr.a6) ||
754 !ipv6_addr_equal((struct in6_addr *)saddr,
755 (struct in6_addr *)
756 x->props.saddr.a6))
757 continue;
758 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700759 }
David S. Milleredcd5822006-08-24 00:42:45 -0700760
761 xfrm_state_hold(x);
762 return x;
763 }
764
765 return NULL;
766}
767
768static inline struct xfrm_state *
769__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
770{
771 if (use_spi)
772 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
773 x->id.proto, family);
774 else
775 return __xfrm_state_lookup_byaddr(&x->id.daddr,
776 &x->props.saddr,
777 x->id.proto, family);
778}
779
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700780static void xfrm_hash_grow_check(int have_hash_collision)
781{
782 if (have_hash_collision &&
783 (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
784 xfrm_state_num > xfrm_state_hmask)
785 schedule_work(&xfrm_hash_work);
786}
787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900789xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 struct flowi *fl, struct xfrm_tmpl *tmpl,
791 struct xfrm_policy *pol, int *err,
792 unsigned short family)
793{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800794 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700795 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700796 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 int acquire_in_progress = 0;
798 int error = 0;
799 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900800
David S. Miller37b08e32008-09-02 20:14:15 -0700801 to_put = NULL;
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800804 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700805 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (x->props.family == family &&
807 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700808 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 xfrm_state_addr_check(x, daddr, saddr, family) &&
810 tmpl->mode == x->props.mode &&
811 tmpl->id.proto == x->id.proto &&
812 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
813 /* Resolution logic:
814 1. There is a valid state with matching selector.
815 Done.
816 2. Valid state with inappropriate selector. Skip.
817
818 Entering area of "sysdeps".
819
820 3. If state is not valid, selector is temporary,
821 it selects only session which triggered
822 previous resolution. Key manager will do
823 something to install a state with proper
824 selector.
825 */
826 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700827 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700828 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 continue;
830 if (!best ||
831 best->km.dying > x->km.dying ||
832 (best->km.dying == x->km.dying &&
833 best->curlft.add_time < x->curlft.add_time))
834 best = x;
835 } else if (x->km.state == XFRM_STATE_ACQ) {
836 acquire_in_progress = 1;
837 } else if (x->km.state == XFRM_STATE_ERROR ||
838 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700839 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700840 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 error = -ESRCH;
842 }
843 }
844 }
845
846 x = best;
847 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700848 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700849 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
850 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700851 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 error = -EEXIST;
853 goto out;
854 }
855 x = xfrm_state_alloc();
856 if (x == NULL) {
857 error = -ENOMEM;
858 goto out;
859 }
860 /* Initialize temporary selector matching only
861 * to current session. */
862 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
863
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700864 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
865 if (error) {
866 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700867 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700868 x = NULL;
869 goto out;
870 }
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (km_query(x, tmpl, pol) == 0) {
873 x->km.state = XFRM_STATE_ACQ;
Herbert Xu225f4002008-09-09 05:23:37 -0700874 list_add_tail(&x->all, &xfrm_state_all);
David S. Miller8f126e32006-08-24 02:45:07 -0700875 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700876 h = xfrm_src_hash(daddr, saddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700877 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (x->id.spi) {
879 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700880 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
David S. Miller01e67d02007-05-25 00:41:38 -0700882 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
883 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 add_timer(&x->timer);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700885 xfrm_state_num++;
886 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 } else {
888 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700889 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 x = NULL;
891 error = -ESRCH;
892 }
893 }
894out:
895 if (x)
896 xfrm_state_hold(x);
897 else
898 *err = acquire_in_progress ? -EAGAIN : error;
899 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700900 if (to_put)
901 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return x;
903}
904
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700905struct xfrm_state *
906xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
907 unsigned short family, u8 mode, u8 proto, u32 reqid)
908{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800909 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700910 struct xfrm_state *rx = NULL, *x = NULL;
911 struct hlist_node *entry;
912
913 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800914 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700915 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
916 if (x->props.family == family &&
917 x->props.reqid == reqid &&
918 !(x->props.flags & XFRM_STATE_WILDRECV) &&
919 xfrm_state_addr_check(x, daddr, saddr, family) &&
920 mode == x->props.mode &&
921 proto == x->id.proto &&
922 x->km.state == XFRM_STATE_VALID) {
923 rx = x;
924 break;
925 }
926 }
927
928 if (rx)
929 xfrm_state_hold(rx);
930 spin_unlock(&xfrm_state_lock);
931
932
933 return rx;
934}
935EXPORT_SYMBOL(xfrm_stateonly_find);
936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937static void __xfrm_state_insert(struct xfrm_state *x)
938{
David S. Millera624c102006-08-24 03:24:33 -0700939 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
David S. Miller9d4a7062006-08-24 03:18:09 -0700941 x->genid = ++xfrm_state_genid;
942
Timo Teras4c563f72008-02-28 21:31:08 -0800943 list_add_tail(&x->all, &xfrm_state_all);
944
David S. Millerc1969f22006-08-24 04:00:03 -0700945 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
946 x->props.reqid, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -0700947 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700949 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -0700950 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700952 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700953 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
954 x->props.family);
955
David S. Miller8f126e32006-08-24 02:45:07 -0700956 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700957 }
958
David S. Millera47f0ce2006-08-24 03:54:22 -0700959 mod_timer(&x->timer, jiffies + HZ);
960 if (x->replay_maxage)
961 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700964
965 xfrm_state_num++;
966
David S. Miller918049f2006-10-12 22:03:24 -0700967 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968}
969
David S. Millerc7f5ea32006-08-24 03:29:04 -0700970/* xfrm_state_lock is held */
971static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
972{
973 unsigned short family = xnew->props.family;
974 u32 reqid = xnew->props.reqid;
975 struct xfrm_state *x;
976 struct hlist_node *entry;
977 unsigned int h;
978
David S. Millerc1969f22006-08-24 04:00:03 -0700979 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700980 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
981 if (x->props.family == family &&
982 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700983 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
984 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700985 x->genid = xfrm_state_genid;
986 }
987}
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989void xfrm_state_insert(struct xfrm_state *x)
990{
991 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700992 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 __xfrm_state_insert(x);
994 spin_unlock_bh(&xfrm_state_lock);
995}
996EXPORT_SYMBOL(xfrm_state_insert);
997
David S. Miller27708342006-08-24 00:13:10 -0700998/* xfrm_state_lock is held */
999static 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)
1000{
David S. Millerc1969f22006-08-24 04:00:03 -07001001 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -07001002 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -07001003 struct xfrm_state *x;
1004
David S. Miller8f126e32006-08-24 02:45:07 -07001005 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -07001006 if (x->props.reqid != reqid ||
1007 x->props.mode != mode ||
1008 x->props.family != family ||
1009 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -07001010 x->id.spi != 0 ||
1011 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -07001012 continue;
1013
1014 switch (family) {
1015 case AF_INET:
1016 if (x->id.daddr.a4 != daddr->a4 ||
1017 x->props.saddr.a4 != saddr->a4)
1018 continue;
1019 break;
1020 case AF_INET6:
1021 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
1022 (struct in6_addr *)daddr) ||
1023 !ipv6_addr_equal((struct in6_addr *)
1024 x->props.saddr.a6,
1025 (struct in6_addr *)saddr))
1026 continue;
1027 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001028 }
David S. Miller27708342006-08-24 00:13:10 -07001029
1030 xfrm_state_hold(x);
1031 return x;
1032 }
1033
1034 if (!create)
1035 return NULL;
1036
1037 x = xfrm_state_alloc();
1038 if (likely(x)) {
1039 switch (family) {
1040 case AF_INET:
1041 x->sel.daddr.a4 = daddr->a4;
1042 x->sel.saddr.a4 = saddr->a4;
1043 x->sel.prefixlen_d = 32;
1044 x->sel.prefixlen_s = 32;
1045 x->props.saddr.a4 = saddr->a4;
1046 x->id.daddr.a4 = daddr->a4;
1047 break;
1048
1049 case AF_INET6:
1050 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1051 (struct in6_addr *)daddr);
1052 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1053 (struct in6_addr *)saddr);
1054 x->sel.prefixlen_d = 128;
1055 x->sel.prefixlen_s = 128;
1056 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1057 (struct in6_addr *)saddr);
1058 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1059 (struct in6_addr *)daddr);
1060 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001061 }
David S. Miller27708342006-08-24 00:13:10 -07001062
1063 x->km.state = XFRM_STATE_ACQ;
1064 x->id.proto = proto;
1065 x->props.family = family;
1066 x->props.mode = mode;
1067 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001068 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001069 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001070 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001071 add_timer(&x->timer);
Herbert Xu225f4002008-09-09 05:23:37 -07001072 list_add_tail(&x->all, &xfrm_state_all);
David S. Miller8f126e32006-08-24 02:45:07 -07001073 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001074 h = xfrm_src_hash(daddr, saddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -07001075 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001076
1077 xfrm_state_num++;
1078
1079 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001080 }
1081
1082 return x;
1083}
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1086
1087int xfrm_state_add(struct xfrm_state *x)
1088{
David S. Miller37b08e32008-09-02 20:14:15 -07001089 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 int family;
1091 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001092 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
David S. Miller37b08e32008-09-02 20:14:15 -07001096 to_put = NULL;
1097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 spin_lock_bh(&xfrm_state_lock);
1099
David S. Milleredcd5822006-08-24 00:42:45 -07001100 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001102 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 x1 = NULL;
1104 err = -EEXIST;
1105 goto out;
1106 }
1107
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001108 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001110 if (x1 && ((x1->id.proto != x->id.proto) ||
1111 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001112 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 x1 = NULL;
1114 }
1115 }
1116
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001117 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001118 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1119 x->id.proto,
1120 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
David S. Millerc7f5ea32006-08-24 03:29:04 -07001122 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 __xfrm_state_insert(x);
1124 err = 0;
1125
1126out:
1127 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 if (x1) {
1130 xfrm_state_delete(x1);
1131 xfrm_state_put(x1);
1132 }
1133
David S. Miller37b08e32008-09-02 20:14:15 -07001134 if (to_put)
1135 xfrm_state_put(to_put);
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 return err;
1138}
1139EXPORT_SYMBOL(xfrm_state_add);
1140
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001141#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001142static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001143{
1144 int err = -ENOMEM;
1145 struct xfrm_state *x = xfrm_state_alloc();
1146 if (!x)
1147 goto error;
1148
1149 memcpy(&x->id, &orig->id, sizeof(x->id));
1150 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1151 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1152 x->props.mode = orig->props.mode;
1153 x->props.replay_window = orig->props.replay_window;
1154 x->props.reqid = orig->props.reqid;
1155 x->props.family = orig->props.family;
1156 x->props.saddr = orig->props.saddr;
1157
1158 if (orig->aalg) {
1159 x->aalg = xfrm_algo_clone(orig->aalg);
1160 if (!x->aalg)
1161 goto error;
1162 }
1163 x->props.aalgo = orig->props.aalgo;
1164
1165 if (orig->ealg) {
1166 x->ealg = xfrm_algo_clone(orig->ealg);
1167 if (!x->ealg)
1168 goto error;
1169 }
1170 x->props.ealgo = orig->props.ealgo;
1171
1172 if (orig->calg) {
1173 x->calg = xfrm_algo_clone(orig->calg);
1174 if (!x->calg)
1175 goto error;
1176 }
1177 x->props.calgo = orig->props.calgo;
1178
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001179 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001180 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1181 if (!x->encap)
1182 goto error;
1183 }
1184
1185 if (orig->coaddr) {
1186 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1187 GFP_KERNEL);
1188 if (!x->coaddr)
1189 goto error;
1190 }
1191
1192 err = xfrm_init_state(x);
1193 if (err)
1194 goto error;
1195
1196 x->props.flags = orig->props.flags;
1197
1198 x->curlft.add_time = orig->curlft.add_time;
1199 x->km.state = orig->km.state;
1200 x->km.seq = orig->km.seq;
1201
1202 return x;
1203
1204 error:
1205 if (errp)
1206 *errp = err;
1207 if (x) {
1208 kfree(x->aalg);
1209 kfree(x->ealg);
1210 kfree(x->calg);
1211 kfree(x->encap);
1212 kfree(x->coaddr);
1213 }
1214 kfree(x);
1215 return NULL;
1216}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001217
1218/* xfrm_state_lock is held */
1219struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1220{
1221 unsigned int h;
1222 struct xfrm_state *x;
1223 struct hlist_node *entry;
1224
1225 if (m->reqid) {
1226 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1227 m->reqid, m->old_family);
1228 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
1229 if (x->props.mode != m->mode ||
1230 x->id.proto != m->proto)
1231 continue;
1232 if (m->reqid && x->props.reqid != m->reqid)
1233 continue;
1234 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1235 m->old_family) ||
1236 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1237 m->old_family))
1238 continue;
1239 xfrm_state_hold(x);
1240 return x;
1241 }
1242 } else {
1243 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1244 m->old_family);
1245 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
1246 if (x->props.mode != m->mode ||
1247 x->id.proto != m->proto)
1248 continue;
1249 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1250 m->old_family) ||
1251 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1252 m->old_family))
1253 continue;
1254 xfrm_state_hold(x);
1255 return x;
1256 }
1257 }
1258
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001259 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001260}
1261EXPORT_SYMBOL(xfrm_migrate_state_find);
1262
1263struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1264 struct xfrm_migrate *m)
1265{
1266 struct xfrm_state *xc;
1267 int err;
1268
1269 xc = xfrm_state_clone(x, &err);
1270 if (!xc)
1271 return NULL;
1272
1273 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1274 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1275
1276 /* add state */
1277 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1278 /* a care is needed when the destination address of the
1279 state is to be updated as it is a part of triplet */
1280 xfrm_state_insert(xc);
1281 } else {
1282 if ((err = xfrm_state_add(xc)) < 0)
1283 goto error;
1284 }
1285
1286 return xc;
1287error:
1288 kfree(xc);
1289 return NULL;
1290}
1291EXPORT_SYMBOL(xfrm_state_migrate);
1292#endif
1293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294int xfrm_state_update(struct xfrm_state *x)
1295{
David S. Miller37b08e32008-09-02 20:14:15 -07001296 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001298 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
David S. Miller37b08e32008-09-02 20:14:15 -07001300 to_put = NULL;
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001303 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 err = -ESRCH;
1306 if (!x1)
1307 goto out;
1308
1309 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001310 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 err = -EEXIST;
1312 goto out;
1313 }
1314
1315 if (x1->km.state == XFRM_STATE_ACQ) {
1316 __xfrm_state_insert(x);
1317 x = NULL;
1318 }
1319 err = 0;
1320
1321out:
1322 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
David S. Miller37b08e32008-09-02 20:14:15 -07001324 if (to_put)
1325 xfrm_state_put(to_put);
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (err)
1328 return err;
1329
1330 if (!x) {
1331 xfrm_state_delete(x1);
1332 xfrm_state_put(x1);
1333 return 0;
1334 }
1335
1336 err = -EINVAL;
1337 spin_lock_bh(&x1->lock);
1338 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1339 if (x->encap && x1->encap)
1340 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001341 if (x->coaddr && x1->coaddr) {
1342 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1343 }
1344 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1345 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1347 x1->km.dying = 0;
1348
David S. Millera47f0ce2006-08-24 03:54:22 -07001349 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (x1->curlft.use_time)
1351 xfrm_state_check_expire(x1);
1352
1353 err = 0;
1354 }
1355 spin_unlock_bh(&x1->lock);
1356
1357 xfrm_state_put(x1);
1358
1359 return err;
1360}
1361EXPORT_SYMBOL(xfrm_state_update);
1362
1363int xfrm_state_check_expire(struct xfrm_state *x)
1364{
1365 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001366 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 if (x->km.state != XFRM_STATE_VALID)
1369 return -EINVAL;
1370
1371 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1372 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001373 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001374 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 return -EINVAL;
1376 }
1377
1378 if (!x->km.dying &&
1379 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001380 x->curlft.packets >= x->lft.soft_packet_limit)) {
1381 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001382 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 return 0;
1385}
1386EXPORT_SYMBOL(xfrm_state_check_expire);
1387
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001389xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 unsigned short family)
1391{
1392 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001395 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 return x;
1398}
1399EXPORT_SYMBOL(xfrm_state_lookup);
1400
1401struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001402xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1403 u8 proto, unsigned short family)
1404{
1405 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001406
1407 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001408 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001409 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001410 return x;
1411}
1412EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1413
1414struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001415xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1416 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 int create, unsigned short family)
1418{
1419 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001422 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 return x;
1426}
1427EXPORT_SYMBOL(xfrm_find_acq);
1428
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001429#ifdef CONFIG_XFRM_SUB_POLICY
1430int
1431xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1432 unsigned short family)
1433{
1434 int err = 0;
1435 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1436 if (!afinfo)
1437 return -EAFNOSUPPORT;
1438
1439 spin_lock_bh(&xfrm_state_lock);
1440 if (afinfo->tmpl_sort)
1441 err = afinfo->tmpl_sort(dst, src, n);
1442 spin_unlock_bh(&xfrm_state_lock);
1443 xfrm_state_put_afinfo(afinfo);
1444 return err;
1445}
1446EXPORT_SYMBOL(xfrm_tmpl_sort);
1447
1448int
1449xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1450 unsigned short family)
1451{
1452 int err = 0;
1453 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1454 if (!afinfo)
1455 return -EAFNOSUPPORT;
1456
1457 spin_lock_bh(&xfrm_state_lock);
1458 if (afinfo->state_sort)
1459 err = afinfo->state_sort(dst, src, n);
1460 spin_unlock_bh(&xfrm_state_lock);
1461 xfrm_state_put_afinfo(afinfo);
1462 return err;
1463}
1464EXPORT_SYMBOL(xfrm_state_sort);
1465#endif
1466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467/* Silly enough, but I'm lazy to build resolution list */
1468
1469static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1470{
1471 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
David S. Millerf034b5d2006-08-24 03:08:07 -07001473 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001474 struct hlist_node *entry;
1475 struct xfrm_state *x;
1476
1477 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
1478 if (x->km.seq == seq &&
1479 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 xfrm_state_hold(x);
1481 return x;
1482 }
1483 }
1484 }
1485 return NULL;
1486}
1487
1488struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1489{
1490 struct xfrm_state *x;
1491
1492 spin_lock_bh(&xfrm_state_lock);
1493 x = __xfrm_find_acq_byseq(seq);
1494 spin_unlock_bh(&xfrm_state_lock);
1495 return x;
1496}
1497EXPORT_SYMBOL(xfrm_find_acq_byseq);
1498
1499u32 xfrm_get_acqseq(void)
1500{
1501 u32 res;
1502 static u32 acqseq;
1503 static DEFINE_SPINLOCK(acqseq_lock);
1504
1505 spin_lock_bh(&acqseq_lock);
1506 res = (++acqseq ? : ++acqseq);
1507 spin_unlock_bh(&acqseq_lock);
1508 return res;
1509}
1510EXPORT_SYMBOL(xfrm_get_acqseq);
1511
Herbert Xu658b2192007-10-09 13:29:52 -07001512int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513{
David S. Millerf034b5d2006-08-24 03:08:07 -07001514 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001516 int err = -ENOENT;
1517 __be32 minspi = htonl(low);
1518 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Herbert Xu658b2192007-10-09 13:29:52 -07001520 spin_lock_bh(&x->lock);
1521 if (x->km.state == XFRM_STATE_DEAD)
1522 goto unlock;
1523
1524 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001526 goto unlock;
1527
1528 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 if (minspi == maxspi) {
1531 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1532 if (x0) {
1533 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001534 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 }
1536 x->id.spi = minspi;
1537 } else {
1538 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001539 for (h=0; h<high-low+1; h++) {
1540 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1542 if (x0 == NULL) {
1543 x->id.spi = htonl(spi);
1544 break;
1545 }
1546 xfrm_state_put(x0);
1547 }
1548 }
1549 if (x->id.spi) {
1550 spin_lock_bh(&xfrm_state_lock);
1551 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -07001552 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001554
1555 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
Herbert Xu658b2192007-10-09 13:29:52 -07001557
1558unlock:
1559 spin_unlock_bh(&x->lock);
1560
1561 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562}
1563EXPORT_SYMBOL(xfrm_alloc_spi);
1564
Timo Teras4c563f72008-02-28 21:31:08 -08001565int xfrm_state_walk(struct xfrm_state_walk *walk,
1566 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 void *data)
1568{
Timo Teras4c563f72008-02-28 21:31:08 -08001569 struct xfrm_state *old, *x, *last = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 int err = 0;
1571
Timo Teras4c563f72008-02-28 21:31:08 -08001572 if (walk->state == NULL && walk->count != 0)
1573 return 0;
1574
1575 old = x = walk->state;
1576 walk->state = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 spin_lock_bh(&xfrm_state_lock);
Timo Teras4c563f72008-02-28 21:31:08 -08001578 if (x == NULL)
1579 x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
1580 list_for_each_entry_from(x, &xfrm_state_all, all) {
1581 if (x->km.state == XFRM_STATE_DEAD)
1582 continue;
1583 if (!xfrm_id_proto_match(x->id.proto, walk->proto))
1584 continue;
1585 if (last) {
1586 err = func(last, walk->count, data);
1587 if (err) {
1588 xfrm_state_hold(last);
1589 walk->state = last;
1590 goto out;
Jamal Hadi Salim94b9bb52006-12-04 20:03:35 -08001591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 }
Timo Teras4c563f72008-02-28 21:31:08 -08001593 last = x;
1594 walk->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 }
Timo Teras4c563f72008-02-28 21:31:08 -08001596 if (walk->count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 err = -ENOENT;
1598 goto out;
1599 }
Timo Teras4c563f72008-02-28 21:31:08 -08001600 if (last)
1601 err = func(last, 0, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602out:
1603 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu5c182452008-09-22 19:48:19 -07001604 if (old != NULL)
Timo Teras4c563f72008-02-28 21:31:08 -08001605 xfrm_state_put(old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 return err;
1607}
1608EXPORT_SYMBOL(xfrm_state_walk);
1609
Herbert Xu5c182452008-09-22 19:48:19 -07001610void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1611{
1612 walk->proto = proto;
1613 walk->state = NULL;
1614 walk->count = 0;
1615 list_add_tail(&walk->list, &xfrm_state_walks);
1616 walk->genid = ++xfrm_state_walk_ongoing;
1617}
1618EXPORT_SYMBOL(xfrm_state_walk_init);
1619
Herbert Xuabb81c42008-09-09 19:58:29 -07001620void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1621{
Herbert Xu5c182452008-09-22 19:48:19 -07001622 struct list_head *prev;
1623
Herbert Xuabb81c42008-09-09 19:58:29 -07001624 if (walk->state != NULL) {
1625 xfrm_state_put(walk->state);
1626 walk->state = NULL;
Herbert Xuabb81c42008-09-09 19:58:29 -07001627 }
Herbert Xu5c182452008-09-22 19:48:19 -07001628
1629 prev = walk->list.prev;
1630 list_del(&walk->list);
1631
1632 if (prev != &xfrm_state_walks) {
1633 list_entry(prev, struct xfrm_state_walk, list)->genid =
1634 walk->genid;
1635 return;
1636 }
1637
1638 xfrm_state_walk_completed = walk->genid;
1639
1640 if (!list_empty(&xfrm_state_gc_leftovers))
1641 schedule_work(&xfrm_state_gc_work);
Herbert Xuabb81c42008-09-09 19:58:29 -07001642}
1643EXPORT_SYMBOL(xfrm_state_walk_done);
1644
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001645
1646void xfrm_replay_notify(struct xfrm_state *x, int event)
1647{
1648 struct km_event c;
1649 /* we send notify messages in case
1650 * 1. we updated on of the sequence numbers, and the seqno difference
1651 * is at least x->replay_maxdiff, in this case we also update the
1652 * timeout of our timer function
1653 * 2. if x->replay_maxage has elapsed since last update,
1654 * and there were changes
1655 *
1656 * The state structure must be locked!
1657 */
1658
1659 switch (event) {
1660 case XFRM_REPLAY_UPDATE:
1661 if (x->replay_maxdiff &&
1662 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001663 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1664 if (x->xflags & XFRM_TIME_DEFER)
1665 event = XFRM_REPLAY_TIMEOUT;
1666 else
1667 return;
1668 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001669
1670 break;
1671
1672 case XFRM_REPLAY_TIMEOUT:
1673 if ((x->replay.seq == x->preplay.seq) &&
1674 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001675 (x->replay.oseq == x->preplay.oseq)) {
1676 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001677 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001678 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001679
1680 break;
1681 }
1682
1683 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1684 c.event = XFRM_MSG_NEWAE;
1685 c.data.aevent = event;
1686 km_state_notify(x, &c);
1687
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001688 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001689 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001690 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001691}
1692
1693static void xfrm_replay_timer_handler(unsigned long data)
1694{
1695 struct xfrm_state *x = (struct xfrm_state*)data;
1696
1697 spin_lock(&x->lock);
1698
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001699 if (x->km.state == XFRM_STATE_VALID) {
1700 if (xfrm_aevent_is_on())
1701 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1702 else
1703 x->xflags |= XFRM_TIME_DEFER;
1704 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001705
1706 spin_unlock(&x->lock);
1707}
1708
Paul Mooreafeb14b2007-12-21 14:58:11 -08001709int xfrm_replay_check(struct xfrm_state *x,
1710 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711{
1712 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001713 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001716 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718 if (likely(seq > x->replay.seq))
1719 return 0;
1720
1721 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001722 if (diff >= min_t(unsigned int, x->props.replay_window,
1723 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001725 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 }
1727
1728 if (x->replay.bitmap & (1U << diff)) {
1729 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001730 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 }
1732 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001733
1734err:
1735 xfrm_audit_state_replay(x, skb, net_seq);
1736 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Al Viro61f46272006-09-27 18:48:33 -07001739void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740{
1741 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001742 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
1744 if (seq > x->replay.seq) {
1745 diff = seq - x->replay.seq;
1746 if (diff < x->props.replay_window)
1747 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1748 else
1749 x->replay.bitmap = 1;
1750 x->replay.seq = seq;
1751 } else {
1752 diff = x->replay.seq - seq;
1753 x->replay.bitmap |= (1U << diff);
1754 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001755
1756 if (xfrm_aevent_is_on())
1757 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Denis Chengdf018122007-12-07 00:51:11 -08001760static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761static DEFINE_RWLOCK(xfrm_km_lock);
1762
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001763void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764{
1765 struct xfrm_mgr *km;
1766
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001767 read_lock(&xfrm_km_lock);
1768 list_for_each_entry(km, &xfrm_km_list, list)
1769 if (km->notify_policy)
1770 km->notify_policy(xp, dir, c);
1771 read_unlock(&xfrm_km_lock);
1772}
1773
1774void km_state_notify(struct xfrm_state *x, struct km_event *c)
1775{
1776 struct xfrm_mgr *km;
1777 read_lock(&xfrm_km_lock);
1778 list_for_each_entry(km, &xfrm_km_list, list)
1779 if (km->notify)
1780 km->notify(x, c);
1781 read_unlock(&xfrm_km_lock);
1782}
1783
1784EXPORT_SYMBOL(km_policy_notify);
1785EXPORT_SYMBOL(km_state_notify);
1786
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001787void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001788{
1789 struct km_event c;
1790
Herbert Xubf088672005-06-18 22:44:00 -07001791 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001792 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001793 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001794 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
1796 if (hard)
1797 wake_up(&km_waitq);
1798}
1799
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001800EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001801/*
1802 * We send to all registered managers regardless of failure
1803 * We are happy with one success
1804*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001805int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001807 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 struct xfrm_mgr *km;
1809
1810 read_lock(&xfrm_km_lock);
1811 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001812 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1813 if (!acqret)
1814 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 }
1816 read_unlock(&xfrm_km_lock);
1817 return err;
1818}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001819EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
Al Viro5d36b182006-11-08 00:24:06 -08001821int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822{
1823 int err = -EINVAL;
1824 struct xfrm_mgr *km;
1825
1826 read_lock(&xfrm_km_lock);
1827 list_for_each_entry(km, &xfrm_km_list, list) {
1828 if (km->new_mapping)
1829 err = km->new_mapping(x, ipaddr, sport);
1830 if (!err)
1831 break;
1832 }
1833 read_unlock(&xfrm_km_lock);
1834 return err;
1835}
1836EXPORT_SYMBOL(km_new_mapping);
1837
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001838void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001840 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Herbert Xubf088672005-06-18 22:44:00 -07001842 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001843 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001844 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001845 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 if (hard)
1848 wake_up(&km_waitq);
1849}
David S. Millera70fcb02006-03-20 19:18:52 -08001850EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001852#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001853int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1854 struct xfrm_migrate *m, int num_migrate)
1855{
1856 int err = -EINVAL;
1857 int ret;
1858 struct xfrm_mgr *km;
1859
1860 read_lock(&xfrm_km_lock);
1861 list_for_each_entry(km, &xfrm_km_list, list) {
1862 if (km->migrate) {
1863 ret = km->migrate(sel, dir, type, m, num_migrate);
1864 if (!ret)
1865 err = ret;
1866 }
1867 }
1868 read_unlock(&xfrm_km_lock);
1869 return err;
1870}
1871EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001872#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001873
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001874int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1875{
1876 int err = -EINVAL;
1877 int ret;
1878 struct xfrm_mgr *km;
1879
1880 read_lock(&xfrm_km_lock);
1881 list_for_each_entry(km, &xfrm_km_list, list) {
1882 if (km->report) {
1883 ret = km->report(proto, sel, addr);
1884 if (!ret)
1885 err = ret;
1886 }
1887 }
1888 read_unlock(&xfrm_km_lock);
1889 return err;
1890}
1891EXPORT_SYMBOL(km_report);
1892
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1894{
1895 int err;
1896 u8 *data;
1897 struct xfrm_mgr *km;
1898 struct xfrm_policy *pol = NULL;
1899
1900 if (optlen <= 0 || optlen > PAGE_SIZE)
1901 return -EMSGSIZE;
1902
1903 data = kmalloc(optlen, GFP_KERNEL);
1904 if (!data)
1905 return -ENOMEM;
1906
1907 err = -EFAULT;
1908 if (copy_from_user(data, optval, optlen))
1909 goto out;
1910
1911 err = -EINVAL;
1912 read_lock(&xfrm_km_lock);
1913 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001914 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 optlen, &err);
1916 if (err >= 0)
1917 break;
1918 }
1919 read_unlock(&xfrm_km_lock);
1920
1921 if (err >= 0) {
1922 xfrm_sk_policy_insert(sk, err, pol);
1923 xfrm_pol_put(pol);
1924 err = 0;
1925 }
1926
1927out:
1928 kfree(data);
1929 return err;
1930}
1931EXPORT_SYMBOL(xfrm_user_policy);
1932
1933int xfrm_register_km(struct xfrm_mgr *km)
1934{
1935 write_lock_bh(&xfrm_km_lock);
1936 list_add_tail(&km->list, &xfrm_km_list);
1937 write_unlock_bh(&xfrm_km_lock);
1938 return 0;
1939}
1940EXPORT_SYMBOL(xfrm_register_km);
1941
1942int xfrm_unregister_km(struct xfrm_mgr *km)
1943{
1944 write_lock_bh(&xfrm_km_lock);
1945 list_del(&km->list);
1946 write_unlock_bh(&xfrm_km_lock);
1947 return 0;
1948}
1949EXPORT_SYMBOL(xfrm_unregister_km);
1950
1951int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1952{
1953 int err = 0;
1954 if (unlikely(afinfo == NULL))
1955 return -EINVAL;
1956 if (unlikely(afinfo->family >= NPROTO))
1957 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001958 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1960 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001961 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001963 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 return err;
1965}
1966EXPORT_SYMBOL(xfrm_state_register_afinfo);
1967
1968int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1969{
1970 int err = 0;
1971 if (unlikely(afinfo == NULL))
1972 return -EINVAL;
1973 if (unlikely(afinfo->family >= NPROTO))
1974 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001975 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1977 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1978 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001979 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001982 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 return err;
1984}
1985EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1986
Herbert Xu17c2a422007-10-17 21:33:12 -07001987static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988{
1989 struct xfrm_state_afinfo *afinfo;
1990 if (unlikely(family >= NPROTO))
1991 return NULL;
1992 read_lock(&xfrm_state_afinfo_lock);
1993 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001994 if (unlikely(!afinfo))
1995 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 return afinfo;
1997}
1998
Herbert Xu17c2a422007-10-17 21:33:12 -07001999static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08002000 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
Herbert Xu546be242006-05-27 23:03:58 -07002002 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003}
2004
2005/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
2006void xfrm_state_delete_tunnel(struct xfrm_state *x)
2007{
2008 if (x->tunnel) {
2009 struct xfrm_state *t = x->tunnel;
2010
2011 if (atomic_read(&t->tunnel_users) == 2)
2012 xfrm_state_delete(t);
2013 atomic_dec(&t->tunnel_users);
2014 xfrm_state_put(t);
2015 x->tunnel = NULL;
2016 }
2017}
2018EXPORT_SYMBOL(xfrm_state_delete_tunnel);
2019
2020int xfrm_state_mtu(struct xfrm_state *x, int mtu)
2021{
Patrick McHardyc5c25232007-04-09 11:47:18 -07002022 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
Patrick McHardyc5c25232007-04-09 11:47:18 -07002024 spin_lock_bh(&x->lock);
2025 if (x->km.state == XFRM_STATE_VALID &&
2026 x->type && x->type->get_mtu)
2027 res = x->type->get_mtu(x, mtu);
2028 else
Patrick McHardy28121612007-06-18 22:30:15 -07002029 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07002030 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 return res;
2032}
2033
Herbert Xu72cb6962005-06-20 13:18:08 -07002034int xfrm_init_state(struct xfrm_state *x)
2035{
Herbert Xud094cd82005-06-20 13:19:41 -07002036 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002037 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07002038 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07002039 int err;
2040
Herbert Xud094cd82005-06-20 13:19:41 -07002041 err = -EAFNOSUPPORT;
2042 afinfo = xfrm_state_get_afinfo(family);
2043 if (!afinfo)
2044 goto error;
2045
2046 err = 0;
2047 if (afinfo->init_flags)
2048 err = afinfo->init_flags(x);
2049
2050 xfrm_state_put_afinfo(afinfo);
2051
2052 if (err)
2053 goto error;
2054
2055 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002056
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002057 if (x->sel.family != AF_UNSPEC) {
2058 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2059 if (inner_mode == NULL)
2060 goto error;
2061
2062 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2063 family != x->sel.family) {
2064 xfrm_put_mode(inner_mode);
2065 goto error;
2066 }
2067
2068 x->inner_mode = inner_mode;
2069 } else {
2070 struct xfrm_mode *inner_mode_iaf;
2071
2072 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2073 if (inner_mode == NULL)
2074 goto error;
2075
2076 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2077 xfrm_put_mode(inner_mode);
2078 goto error;
2079 }
2080
2081 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2082 if (inner_mode_iaf == NULL)
2083 goto error;
2084
2085 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2086 xfrm_put_mode(inner_mode_iaf);
2087 goto error;
2088 }
2089
2090 if (x->props.family == AF_INET) {
2091 x->inner_mode = inner_mode;
2092 x->inner_mode_iaf = inner_mode_iaf;
2093 } else {
2094 x->inner_mode = inner_mode_iaf;
2095 x->inner_mode_iaf = inner_mode;
2096 }
2097 }
Herbert Xu13996372007-10-17 21:35:51 -07002098
Herbert Xud094cd82005-06-20 13:19:41 -07002099 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002100 if (x->type == NULL)
2101 goto error;
2102
2103 err = x->type->init_state(x);
2104 if (err)
2105 goto error;
2106
Herbert Xu13996372007-10-17 21:35:51 -07002107 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2108 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002109 goto error;
2110
Herbert Xu72cb6962005-06-20 13:18:08 -07002111 x->km.state = XFRM_STATE_VALID;
2112
2113error:
2114 return err;
2115}
2116
2117EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002118
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119void __init xfrm_state_init(void)
2120{
David S. Millerf034b5d2006-08-24 03:08:07 -07002121 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
David S. Millerf034b5d2006-08-24 03:08:07 -07002123 sz = sizeof(struct hlist_head) * 8;
2124
David S. Miller44e36b42006-08-24 04:50:50 -07002125 xfrm_state_bydst = xfrm_hash_alloc(sz);
2126 xfrm_state_bysrc = xfrm_hash_alloc(sz);
2127 xfrm_state_byspi = xfrm_hash_alloc(sz);
David S. Millerf034b5d2006-08-24 03:08:07 -07002128 if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
2129 panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
2130 xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
2131
David Howellsc4028952006-11-22 14:57:56 +00002132 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133}
2134
Joy Lattenab5f5e82007-09-17 11:51:22 -07002135#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002136static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2137 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002138{
Paul Moore68277ac2007-12-20 20:49:33 -08002139 struct xfrm_sec_ctx *ctx = x->security;
2140 u32 spi = ntohl(x->id.spi);
2141
2142 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002143 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002144 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002145
2146 switch(x->props.family) {
2147 case AF_INET:
Paul Moore68277ac2007-12-20 20:49:33 -08002148 audit_log_format(audit_buf,
2149 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
Joy Lattenab5f5e82007-09-17 11:51:22 -07002150 NIPQUAD(x->props.saddr.a4),
2151 NIPQUAD(x->id.daddr.a4));
2152 break;
2153 case AF_INET6:
Paul Moore68277ac2007-12-20 20:49:33 -08002154 audit_log_format(audit_buf,
2155 " src=" NIP6_FMT " dst=" NIP6_FMT,
2156 NIP6(*(struct in6_addr *)x->props.saddr.a6),
2157 NIP6(*(struct in6_addr *)x->id.daddr.a6));
Joy Lattenab5f5e82007-09-17 11:51:22 -07002158 break;
2159 }
Paul Moore68277ac2007-12-20 20:49:33 -08002160
2161 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002162}
2163
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002164static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2165 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002166{
2167 struct iphdr *iph4;
2168 struct ipv6hdr *iph6;
2169
2170 switch (family) {
2171 case AF_INET:
2172 iph4 = ip_hdr(skb);
2173 audit_log_format(audit_buf,
2174 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
2175 NIPQUAD(iph4->saddr),
2176 NIPQUAD(iph4->daddr));
2177 break;
2178 case AF_INET6:
2179 iph6 = ipv6_hdr(skb);
2180 audit_log_format(audit_buf,
2181 " src=" NIP6_FMT " dst=" NIP6_FMT
YOSHIFUJI Hideaki5e2c4332008-04-26 22:24:10 -07002182 " flowlbl=0x%x%02x%02x",
Paul Mooreafeb14b2007-12-21 14:58:11 -08002183 NIP6(iph6->saddr),
2184 NIP6(iph6->daddr),
2185 iph6->flow_lbl[0] & 0x0f,
2186 iph6->flow_lbl[1],
2187 iph6->flow_lbl[2]);
2188 break;
2189 }
2190}
2191
Paul Moore68277ac2007-12-20 20:49:33 -08002192void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002193 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002194{
2195 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002196
Paul Mooreafeb14b2007-12-21 14:58:11 -08002197 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002198 if (audit_buf == NULL)
2199 return;
Eric Paris25323862008-04-18 10:09:25 -04002200 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002201 xfrm_audit_helper_sainfo(x, audit_buf);
2202 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002203 audit_log_end(audit_buf);
2204}
2205EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2206
Paul Moore68277ac2007-12-20 20:49:33 -08002207void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002208 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002209{
2210 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002211
Paul Mooreafeb14b2007-12-21 14:58:11 -08002212 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002213 if (audit_buf == NULL)
2214 return;
Eric Paris25323862008-04-18 10:09:25 -04002215 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002216 xfrm_audit_helper_sainfo(x, audit_buf);
2217 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002218 audit_log_end(audit_buf);
2219}
2220EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002221
2222void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2223 struct sk_buff *skb)
2224{
2225 struct audit_buffer *audit_buf;
2226 u32 spi;
2227
2228 audit_buf = xfrm_audit_start("SA-replay-overflow");
2229 if (audit_buf == NULL)
2230 return;
2231 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2232 /* don't record the sequence number because it's inherent in this kind
2233 * of audit message */
2234 spi = ntohl(x->id.spi);
2235 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2236 audit_log_end(audit_buf);
2237}
2238EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2239
2240static void xfrm_audit_state_replay(struct xfrm_state *x,
2241 struct sk_buff *skb, __be32 net_seq)
2242{
2243 struct audit_buffer *audit_buf;
2244 u32 spi;
2245
2246 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2247 if (audit_buf == NULL)
2248 return;
2249 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2250 spi = ntohl(x->id.spi);
2251 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2252 spi, spi, ntohl(net_seq));
2253 audit_log_end(audit_buf);
2254}
2255
2256void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2257{
2258 struct audit_buffer *audit_buf;
2259
2260 audit_buf = xfrm_audit_start("SA-notfound");
2261 if (audit_buf == NULL)
2262 return;
2263 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2264 audit_log_end(audit_buf);
2265}
2266EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2267
2268void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2269 __be32 net_spi, __be32 net_seq)
2270{
2271 struct audit_buffer *audit_buf;
2272 u32 spi;
2273
2274 audit_buf = xfrm_audit_start("SA-notfound");
2275 if (audit_buf == NULL)
2276 return;
2277 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2278 spi = ntohl(net_spi);
2279 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2280 spi, spi, ntohl(net_seq));
2281 audit_log_end(audit_buf);
2282}
2283EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2284
2285void xfrm_audit_state_icvfail(struct xfrm_state *x,
2286 struct sk_buff *skb, u8 proto)
2287{
2288 struct audit_buffer *audit_buf;
2289 __be32 net_spi;
2290 __be32 net_seq;
2291
2292 audit_buf = xfrm_audit_start("SA-icv-failure");
2293 if (audit_buf == NULL)
2294 return;
2295 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2296 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2297 u32 spi = ntohl(net_spi);
2298 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2299 spi, spi, ntohl(net_seq));
2300 }
2301 audit_log_end(audit_buf);
2302}
2303EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002304#endif /* CONFIG_AUDITSYSCALL */