blob: 08b78895ffbcb6ae610e493cb8255c599f2a024e [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
David S. Millerf034b5d2006-08-24 03:08:07 -070047static struct hlist_head *xfrm_state_bysrc __read_mostly;
48static struct hlist_head *xfrm_state_byspi __read_mostly;
49static unsigned int xfrm_state_hmask __read_mostly;
50static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
51static unsigned int xfrm_state_num;
David S. Miller9d4a7062006-08-24 03:18:09 -070052static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Herbert Xu17c2a422007-10-17 21:33:12 -070054static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
55static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
56
Paul Mooreafeb14b2007-12-21 14:58:11 -080057#ifdef CONFIG_AUDITSYSCALL
58static void xfrm_audit_state_replay(struct xfrm_state *x,
59 struct sk_buff *skb, __be32 net_seq);
60#else
61#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
62#endif /* CONFIG_AUDITSYSCALL */
63
David S. Millerc1969f22006-08-24 04:00:03 -070064static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
65 xfrm_address_t *saddr,
66 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070067 unsigned short family)
68{
David S. Millerc1969f22006-08-24 04:00:03 -070069 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070070}
71
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070072static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
73 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070074 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070075{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070076 return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070077}
78
David S. Miller2575b652006-08-24 03:26:44 -070079static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070080xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070081{
David S. Millerc1969f22006-08-24 04:00:03 -070082 return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070083}
84
David S. Millerf034b5d2006-08-24 03:08:07 -070085static void xfrm_hash_transfer(struct hlist_head *list,
86 struct hlist_head *ndsttable,
87 struct hlist_head *nsrctable,
88 struct hlist_head *nspitable,
89 unsigned int nhashmask)
90{
91 struct hlist_node *entry, *tmp;
92 struct xfrm_state *x;
93
94 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
95 unsigned int h;
96
David S. Millerc1969f22006-08-24 04:00:03 -070097 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
98 x->props.reqid, x->props.family,
99 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -0700100 hlist_add_head(&x->bydst, ndsttable+h);
101
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700102 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
103 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700104 nhashmask);
105 hlist_add_head(&x->bysrc, nsrctable+h);
106
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700107 if (x->id.spi) {
108 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
109 x->id.proto, x->props.family,
110 nhashmask);
111 hlist_add_head(&x->byspi, nspitable+h);
112 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700113 }
114}
115
116static unsigned long xfrm_hash_new_size(void)
117{
118 return ((xfrm_state_hmask + 1) << 1) *
119 sizeof(struct hlist_head);
120}
121
122static DEFINE_MUTEX(hash_resize_mutex);
123
David Howellsc4028952006-11-22 14:57:56 +0000124static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700125{
126 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
127 unsigned long nsize, osize;
128 unsigned int nhashmask, ohashmask;
129 int i;
130
131 mutex_lock(&hash_resize_mutex);
132
133 nsize = xfrm_hash_new_size();
David S. Miller44e36b42006-08-24 04:50:50 -0700134 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700135 if (!ndst)
136 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700137 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700138 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700139 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700140 goto out_unlock;
141 }
David S. Miller44e36b42006-08-24 04:50:50 -0700142 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700143 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700144 xfrm_hash_free(ndst, nsize);
145 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700146 goto out_unlock;
147 }
148
149 spin_lock_bh(&xfrm_state_lock);
150
151 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
152 for (i = xfrm_state_hmask; i >= 0; i--)
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800153 xfrm_hash_transfer(init_net.xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700154 nhashmask);
155
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800156 odst = init_net.xfrm.state_bydst;
David S. Millerf034b5d2006-08-24 03:08:07 -0700157 osrc = xfrm_state_bysrc;
158 ospi = xfrm_state_byspi;
159 ohashmask = xfrm_state_hmask;
160
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800161 init_net.xfrm.state_bydst = ndst;
David S. Millerf034b5d2006-08-24 03:08:07 -0700162 xfrm_state_bysrc = nsrc;
163 xfrm_state_byspi = nspi;
164 xfrm_state_hmask = nhashmask;
165
166 spin_unlock_bh(&xfrm_state_lock);
167
168 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700169 xfrm_hash_free(odst, osize);
170 xfrm_hash_free(osrc, osize);
171 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700172
173out_unlock:
174 mutex_unlock(&hash_resize_mutex);
175}
176
David Howellsc4028952006-11-22 14:57:56 +0000177static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700178
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179DECLARE_WAIT_QUEUE_HEAD(km_waitq);
180EXPORT_SYMBOL(km_waitq);
181
182static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
183static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
184
185static struct work_struct xfrm_state_gc_work;
Herbert Xu12a169e2008-10-01 07:03:24 -0700186static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static DEFINE_SPINLOCK(xfrm_state_gc_lock);
188
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800189int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800191int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800192void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700194static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
195{
196 struct xfrm_state_afinfo *afinfo;
197 if (unlikely(family >= NPROTO))
198 return NULL;
199 write_lock_bh(&xfrm_state_afinfo_lock);
200 afinfo = xfrm_state_afinfo[family];
201 if (unlikely(!afinfo))
202 write_unlock_bh(&xfrm_state_afinfo_lock);
203 return afinfo;
204}
205
206static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800207 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700208{
209 write_unlock_bh(&xfrm_state_afinfo_lock);
210}
211
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800212int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700213{
214 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800215 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700216 int err = 0;
217
218 if (unlikely(afinfo == NULL))
219 return -EAFNOSUPPORT;
220 typemap = afinfo->type_map;
221
222 if (likely(typemap[type->proto] == NULL))
223 typemap[type->proto] = type;
224 else
225 err = -EEXIST;
226 xfrm_state_unlock_afinfo(afinfo);
227 return err;
228}
229EXPORT_SYMBOL(xfrm_register_type);
230
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800231int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700232{
233 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800234 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700235 int err = 0;
236
237 if (unlikely(afinfo == NULL))
238 return -EAFNOSUPPORT;
239 typemap = afinfo->type_map;
240
241 if (unlikely(typemap[type->proto] != type))
242 err = -ENOENT;
243 else
244 typemap[type->proto] = NULL;
245 xfrm_state_unlock_afinfo(afinfo);
246 return err;
247}
248EXPORT_SYMBOL(xfrm_unregister_type);
249
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800250static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700251{
252 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800253 const struct xfrm_type **typemap;
254 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700255 int modload_attempted = 0;
256
257retry:
258 afinfo = xfrm_state_get_afinfo(family);
259 if (unlikely(afinfo == NULL))
260 return NULL;
261 typemap = afinfo->type_map;
262
263 type = typemap[proto];
264 if (unlikely(type && !try_module_get(type->owner)))
265 type = NULL;
266 if (!type && !modload_attempted) {
267 xfrm_state_put_afinfo(afinfo);
268 request_module("xfrm-type-%d-%d", family, proto);
269 modload_attempted = 1;
270 goto retry;
271 }
272
273 xfrm_state_put_afinfo(afinfo);
274 return type;
275}
276
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800277static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700278{
279 module_put(type->owner);
280}
281
282int xfrm_register_mode(struct xfrm_mode *mode, int family)
283{
284 struct xfrm_state_afinfo *afinfo;
285 struct xfrm_mode **modemap;
286 int err;
287
288 if (unlikely(mode->encap >= XFRM_MODE_MAX))
289 return -EINVAL;
290
291 afinfo = xfrm_state_lock_afinfo(family);
292 if (unlikely(afinfo == NULL))
293 return -EAFNOSUPPORT;
294
295 err = -EEXIST;
296 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700297 if (modemap[mode->encap])
298 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700299
Herbert Xu17c2a422007-10-17 21:33:12 -0700300 err = -ENOENT;
301 if (!try_module_get(afinfo->owner))
302 goto out;
303
304 mode->afinfo = afinfo;
305 modemap[mode->encap] = mode;
306 err = 0;
307
308out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700309 xfrm_state_unlock_afinfo(afinfo);
310 return err;
311}
312EXPORT_SYMBOL(xfrm_register_mode);
313
314int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
315{
316 struct xfrm_state_afinfo *afinfo;
317 struct xfrm_mode **modemap;
318 int err;
319
320 if (unlikely(mode->encap >= XFRM_MODE_MAX))
321 return -EINVAL;
322
323 afinfo = xfrm_state_lock_afinfo(family);
324 if (unlikely(afinfo == NULL))
325 return -EAFNOSUPPORT;
326
327 err = -ENOENT;
328 modemap = afinfo->mode_map;
329 if (likely(modemap[mode->encap] == mode)) {
330 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700331 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700332 err = 0;
333 }
334
335 xfrm_state_unlock_afinfo(afinfo);
336 return err;
337}
338EXPORT_SYMBOL(xfrm_unregister_mode);
339
340static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
341{
342 struct xfrm_state_afinfo *afinfo;
343 struct xfrm_mode *mode;
344 int modload_attempted = 0;
345
346 if (unlikely(encap >= XFRM_MODE_MAX))
347 return NULL;
348
349retry:
350 afinfo = xfrm_state_get_afinfo(family);
351 if (unlikely(afinfo == NULL))
352 return NULL;
353
354 mode = afinfo->mode_map[encap];
355 if (unlikely(mode && !try_module_get(mode->owner)))
356 mode = NULL;
357 if (!mode && !modload_attempted) {
358 xfrm_state_put_afinfo(afinfo);
359 request_module("xfrm-mode-%d-%d", family, encap);
360 modload_attempted = 1;
361 goto retry;
362 }
363
364 xfrm_state_put_afinfo(afinfo);
365 return mode;
366}
367
368static void xfrm_put_mode(struct xfrm_mode *mode)
369{
370 module_put(mode->owner);
371}
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373static void xfrm_state_gc_destroy(struct xfrm_state *x)
374{
David S. Millera47f0ce2006-08-24 03:54:22 -0700375 del_timer_sync(&x->timer);
376 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800377 kfree(x->aalg);
378 kfree(x->ealg);
379 kfree(x->calg);
380 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700381 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700382 if (x->inner_mode)
383 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700384 if (x->inner_mode_iaf)
385 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700386 if (x->outer_mode)
387 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (x->type) {
389 x->type->destructor(x);
390 xfrm_put_type(x->type);
391 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800392 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 kfree(x);
394}
395
David Howellsc4028952006-11-22 14:57:56 +0000396static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Herbert Xu12a169e2008-10-01 07:03:24 -0700398 struct xfrm_state *x;
399 struct hlist_node *entry, *tmp;
400 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700403 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 spin_unlock_bh(&xfrm_state_gc_lock);
405
Herbert Xu12a169e2008-10-01 07:03:24 -0700406 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 wake_up(&km_waitq);
410}
411
412static inline unsigned long make_jiffies(long secs)
413{
414 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
415 return MAX_SCHEDULE_TIMEOUT-1;
416 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900417 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
419
420static void xfrm_timer_handler(unsigned long data)
421{
422 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800423 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 long next = LONG_MAX;
425 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600426 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 spin_lock(&x->lock);
429 if (x->km.state == XFRM_STATE_DEAD)
430 goto out;
431 if (x->km.state == XFRM_STATE_EXPIRED)
432 goto expired;
433 if (x->lft.hard_add_expires_seconds) {
434 long tmo = x->lft.hard_add_expires_seconds +
435 x->curlft.add_time - now;
436 if (tmo <= 0)
437 goto expired;
438 if (tmo < next)
439 next = tmo;
440 }
441 if (x->lft.hard_use_expires_seconds) {
442 long tmo = x->lft.hard_use_expires_seconds +
443 (x->curlft.use_time ? : now) - now;
444 if (tmo <= 0)
445 goto expired;
446 if (tmo < next)
447 next = tmo;
448 }
449 if (x->km.dying)
450 goto resched;
451 if (x->lft.soft_add_expires_seconds) {
452 long tmo = x->lft.soft_add_expires_seconds +
453 x->curlft.add_time - now;
454 if (tmo <= 0)
455 warn = 1;
456 else if (tmo < next)
457 next = tmo;
458 }
459 if (x->lft.soft_use_expires_seconds) {
460 long tmo = x->lft.soft_use_expires_seconds +
461 (x->curlft.use_time ? : now) - now;
462 if (tmo <= 0)
463 warn = 1;
464 else if (tmo < next)
465 next = tmo;
466 }
467
Herbert Xu4666faa2005-06-18 22:43:22 -0700468 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800470 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700472 if (next != LONG_MAX)
473 mod_timer(&x->timer, jiffies + make_jiffies(next));
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 goto out;
476
477expired:
478 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
479 x->km.state = XFRM_STATE_EXPIRED;
480 wake_up(&km_waitq);
481 next = 2;
482 goto resched;
483 }
Joy Latten161a09e2006-11-27 13:11:54 -0600484
485 err = __xfrm_state_delete(x);
486 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800487 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Joy Lattenab5f5e82007-09-17 11:51:22 -0700489 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400490 audit_get_loginuid(current),
491 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493out:
494 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
David S. Miller0ac84752006-03-20 19:18:23 -0800497static void xfrm_replay_timer_handler(unsigned long data);
498
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800499struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct xfrm_state *x;
502
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700503 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800506 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 atomic_set(&x->refcnt, 1);
508 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700509 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700510 INIT_HLIST_NODE(&x->bydst);
511 INIT_HLIST_NODE(&x->bysrc);
512 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800513 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
514 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
515 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800516 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 x->lft.soft_byte_limit = XFRM_INF;
518 x->lft.soft_packet_limit = XFRM_INF;
519 x->lft.hard_byte_limit = XFRM_INF;
520 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800521 x->replay_maxage = 0;
522 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700523 x->inner_mode = NULL;
524 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 spin_lock_init(&x->lock);
526 }
527 return x;
528}
529EXPORT_SYMBOL(xfrm_state_alloc);
530
531void __xfrm_state_destroy(struct xfrm_state *x)
532{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700533 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700536 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 spin_unlock_bh(&xfrm_state_gc_lock);
538 schedule_work(&xfrm_state_gc_work);
539}
540EXPORT_SYMBOL(__xfrm_state_destroy);
541
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800542int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700544 int err = -ESRCH;
545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 if (x->km.state != XFRM_STATE_DEAD) {
547 x->km.state = XFRM_STATE_DEAD;
548 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700549 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700550 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700551 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700552 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700553 hlist_del(&x->byspi);
David S. Millerf034b5d2006-08-24 03:08:07 -0700554 xfrm_state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /* All xfrm_state objects are created by xfrm_state_alloc.
558 * The xfrm_state_alloc call gives a reference, and that
559 * is what we are dropping here.
560 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800561 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700562 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700564
565 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800567EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700569int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700571 int err;
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700574 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700576
577 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578}
579EXPORT_SYMBOL(xfrm_state_delete);
580
Joy Latten4aa2e622007-06-04 19:05:57 -0400581#ifdef CONFIG_SECURITY_NETWORK_XFRM
582static inline int
583xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
Joy Latten4aa2e622007-06-04 19:05:57 -0400585 int i, err = 0;
586
587 for (i = 0; i <= xfrm_state_hmask; i++) {
588 struct hlist_node *entry;
589 struct xfrm_state *x;
590
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800591 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400592 if (xfrm_id_proto_match(x->id.proto, proto) &&
593 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700594 xfrm_audit_state_delete(x, 0,
595 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400596 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700597 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400598 return err;
599 }
600 }
601 }
602
603 return err;
604}
605#else
606static inline int
607xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
608{
609 return 0;
610}
611#endif
612
613int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
614{
615 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400618 err = xfrm_state_flush_secctx_check(proto, audit_info);
619 if (err)
620 goto out;
621
Masahide NAKAMURAa9917c02006-08-31 15:14:32 -0700622 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700623 struct hlist_node *entry;
624 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800626 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700628 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 xfrm_state_hold(x);
630 spin_unlock_bh(&xfrm_state_lock);
631
Joy Latten161a09e2006-11-27 13:11:54 -0600632 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700633 xfrm_audit_state_delete(x, err ? 0 : 1,
634 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400635 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700636 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 xfrm_state_put(x);
638
639 spin_lock_bh(&xfrm_state_lock);
640 goto restart;
641 }
642 }
643 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400644 err = 0;
645
646out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 spin_unlock_bh(&xfrm_state_lock);
648 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400649 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651EXPORT_SYMBOL(xfrm_state_flush);
652
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700653void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700654{
655 spin_lock_bh(&xfrm_state_lock);
656 si->sadcnt = xfrm_state_num;
657 si->sadhcnt = xfrm_state_hmask;
658 si->sadhmcnt = xfrm_state_hashmax;
659 spin_unlock_bh(&xfrm_state_lock);
660}
661EXPORT_SYMBOL(xfrm_sad_getinfo);
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663static int
664xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
665 struct xfrm_tmpl *tmpl,
666 xfrm_address_t *daddr, xfrm_address_t *saddr,
667 unsigned short family)
668{
669 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
670 if (!afinfo)
671 return -1;
672 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
673 xfrm_state_put_afinfo(afinfo);
674 return 0;
675}
676
Al Viroa94cfd12006-09-27 18:47:24 -0700677static 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 -0700678{
679 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
680 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700681 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700682
David S. Miller8f126e32006-08-24 02:45:07 -0700683 hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700684 if (x->props.family != family ||
685 x->id.spi != spi ||
686 x->id.proto != proto)
687 continue;
688
689 switch (family) {
690 case AF_INET:
691 if (x->id.daddr.a4 != daddr->a4)
692 continue;
693 break;
694 case AF_INET6:
695 if (!ipv6_addr_equal((struct in6_addr *)daddr,
696 (struct in6_addr *)
697 x->id.daddr.a6))
698 continue;
699 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700700 }
David S. Milleredcd5822006-08-24 00:42:45 -0700701
702 xfrm_state_hold(x);
703 return x;
704 }
705
706 return NULL;
707}
708
709static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
710{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700711 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700712 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700713 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700714
David S. Miller8f126e32006-08-24 02:45:07 -0700715 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700716 if (x->props.family != family ||
717 x->id.proto != proto)
718 continue;
719
720 switch (family) {
721 case AF_INET:
722 if (x->id.daddr.a4 != daddr->a4 ||
723 x->props.saddr.a4 != saddr->a4)
724 continue;
725 break;
726 case AF_INET6:
727 if (!ipv6_addr_equal((struct in6_addr *)daddr,
728 (struct in6_addr *)
729 x->id.daddr.a6) ||
730 !ipv6_addr_equal((struct in6_addr *)saddr,
731 (struct in6_addr *)
732 x->props.saddr.a6))
733 continue;
734 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700735 }
David S. Milleredcd5822006-08-24 00:42:45 -0700736
737 xfrm_state_hold(x);
738 return x;
739 }
740
741 return NULL;
742}
743
744static inline struct xfrm_state *
745__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
746{
747 if (use_spi)
748 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
749 x->id.proto, family);
750 else
751 return __xfrm_state_lookup_byaddr(&x->id.daddr,
752 &x->props.saddr,
753 x->id.proto, family);
754}
755
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700756static void xfrm_hash_grow_check(int have_hash_collision)
757{
758 if (have_hash_collision &&
759 (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
760 xfrm_state_num > xfrm_state_hmask)
761 schedule_work(&xfrm_hash_work);
762}
763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900765xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 struct flowi *fl, struct xfrm_tmpl *tmpl,
767 struct xfrm_policy *pol, int *err,
768 unsigned short family)
769{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800770 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700771 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700772 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 int acquire_in_progress = 0;
774 int error = 0;
775 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900776
David S. Miller37b08e32008-09-02 20:14:15 -0700777 to_put = NULL;
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800780 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800781 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (x->props.family == family &&
783 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700784 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 xfrm_state_addr_check(x, daddr, saddr, family) &&
786 tmpl->mode == x->props.mode &&
787 tmpl->id.proto == x->id.proto &&
788 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
789 /* Resolution logic:
790 1. There is a valid state with matching selector.
791 Done.
792 2. Valid state with inappropriate selector. Skip.
793
794 Entering area of "sysdeps".
795
796 3. If state is not valid, selector is temporary,
797 it selects only session which triggered
798 previous resolution. Key manager will do
799 something to install a state with proper
800 selector.
801 */
802 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700803 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700804 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 continue;
806 if (!best ||
807 best->km.dying > x->km.dying ||
808 (best->km.dying == x->km.dying &&
809 best->curlft.add_time < x->curlft.add_time))
810 best = x;
811 } else if (x->km.state == XFRM_STATE_ACQ) {
812 acquire_in_progress = 1;
813 } else if (x->km.state == XFRM_STATE_ERROR ||
814 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700815 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700816 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 error = -ESRCH;
818 }
819 }
820 }
821
822 x = best;
823 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700824 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700825 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
826 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700827 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 error = -EEXIST;
829 goto out;
830 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800831 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (x == NULL) {
833 error = -ENOMEM;
834 goto out;
835 }
836 /* Initialize temporary selector matching only
837 * to current session. */
838 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
839
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700840 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
841 if (error) {
842 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700843 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700844 x = NULL;
845 goto out;
846 }
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (km_query(x, tmpl, pol) == 0) {
849 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800850 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800851 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700852 h = xfrm_src_hash(daddr, saddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700853 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 if (x->id.spi) {
855 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700856 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 }
David S. Miller01e67d02007-05-25 00:41:38 -0700858 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
859 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 add_timer(&x->timer);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700861 xfrm_state_num++;
862 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 } else {
864 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700865 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 x = NULL;
867 error = -ESRCH;
868 }
869 }
870out:
871 if (x)
872 xfrm_state_hold(x);
873 else
874 *err = acquire_in_progress ? -EAGAIN : error;
875 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700876 if (to_put)
877 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return x;
879}
880
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700881struct xfrm_state *
882xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
883 unsigned short family, u8 mode, u8 proto, u32 reqid)
884{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800885 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700886 struct xfrm_state *rx = NULL, *x = NULL;
887 struct hlist_node *entry;
888
889 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800890 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800891 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700892 if (x->props.family == family &&
893 x->props.reqid == reqid &&
894 !(x->props.flags & XFRM_STATE_WILDRECV) &&
895 xfrm_state_addr_check(x, daddr, saddr, family) &&
896 mode == x->props.mode &&
897 proto == x->id.proto &&
898 x->km.state == XFRM_STATE_VALID) {
899 rx = x;
900 break;
901 }
902 }
903
904 if (rx)
905 xfrm_state_hold(rx);
906 spin_unlock(&xfrm_state_lock);
907
908
909 return rx;
910}
911EXPORT_SYMBOL(xfrm_stateonly_find);
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913static void __xfrm_state_insert(struct xfrm_state *x)
914{
David S. Millera624c102006-08-24 03:24:33 -0700915 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
David S. Miller9d4a7062006-08-24 03:18:09 -0700917 x->genid = ++xfrm_state_genid;
918
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800919 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800920
David S. Millerc1969f22006-08-24 04:00:03 -0700921 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
922 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800923 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700925 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -0700926 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700928 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700929 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
930 x->props.family);
931
David S. Miller8f126e32006-08-24 02:45:07 -0700932 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700933 }
934
David S. Millera47f0ce2006-08-24 03:54:22 -0700935 mod_timer(&x->timer, jiffies + HZ);
936 if (x->replay_maxage)
937 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700940
941 xfrm_state_num++;
942
David S. Miller918049f2006-10-12 22:03:24 -0700943 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
David S. Millerc7f5ea32006-08-24 03:29:04 -0700946/* xfrm_state_lock is held */
947static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
948{
949 unsigned short family = xnew->props.family;
950 u32 reqid = xnew->props.reqid;
951 struct xfrm_state *x;
952 struct hlist_node *entry;
953 unsigned int h;
954
David S. Millerc1969f22006-08-24 04:00:03 -0700955 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800956 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700957 if (x->props.family == family &&
958 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700959 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
960 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700961 x->genid = xfrm_state_genid;
962 }
963}
964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965void xfrm_state_insert(struct xfrm_state *x)
966{
967 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700968 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 __xfrm_state_insert(x);
970 spin_unlock_bh(&xfrm_state_lock);
971}
972EXPORT_SYMBOL(xfrm_state_insert);
973
David S. Miller27708342006-08-24 00:13:10 -0700974/* xfrm_state_lock is held */
975static 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)
976{
David S. Millerc1969f22006-08-24 04:00:03 -0700977 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700978 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700979 struct xfrm_state *x;
980
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800981 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700982 if (x->props.reqid != reqid ||
983 x->props.mode != mode ||
984 x->props.family != family ||
985 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700986 x->id.spi != 0 ||
987 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700988 continue;
989
990 switch (family) {
991 case AF_INET:
992 if (x->id.daddr.a4 != daddr->a4 ||
993 x->props.saddr.a4 != saddr->a4)
994 continue;
995 break;
996 case AF_INET6:
997 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
998 (struct in6_addr *)daddr) ||
999 !ipv6_addr_equal((struct in6_addr *)
1000 x->props.saddr.a6,
1001 (struct in6_addr *)saddr))
1002 continue;
1003 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001004 }
David S. Miller27708342006-08-24 00:13:10 -07001005
1006 xfrm_state_hold(x);
1007 return x;
1008 }
1009
1010 if (!create)
1011 return NULL;
1012
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001013 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001014 if (likely(x)) {
1015 switch (family) {
1016 case AF_INET:
1017 x->sel.daddr.a4 = daddr->a4;
1018 x->sel.saddr.a4 = saddr->a4;
1019 x->sel.prefixlen_d = 32;
1020 x->sel.prefixlen_s = 32;
1021 x->props.saddr.a4 = saddr->a4;
1022 x->id.daddr.a4 = daddr->a4;
1023 break;
1024
1025 case AF_INET6:
1026 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1027 (struct in6_addr *)daddr);
1028 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1029 (struct in6_addr *)saddr);
1030 x->sel.prefixlen_d = 128;
1031 x->sel.prefixlen_s = 128;
1032 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1033 (struct in6_addr *)saddr);
1034 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1035 (struct in6_addr *)daddr);
1036 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001037 }
David S. Miller27708342006-08-24 00:13:10 -07001038
1039 x->km.state = XFRM_STATE_ACQ;
1040 x->id.proto = proto;
1041 x->props.family = family;
1042 x->props.mode = mode;
1043 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001044 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001045 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001046 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001047 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001048 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001049 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001050 h = xfrm_src_hash(daddr, saddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -07001051 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001052
1053 xfrm_state_num++;
1054
1055 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001056 }
1057
1058 return x;
1059}
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1062
1063int xfrm_state_add(struct xfrm_state *x)
1064{
David S. Miller37b08e32008-09-02 20:14:15 -07001065 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 int family;
1067 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001068 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
David S. Miller37b08e32008-09-02 20:14:15 -07001072 to_put = NULL;
1073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 spin_lock_bh(&xfrm_state_lock);
1075
David S. Milleredcd5822006-08-24 00:42:45 -07001076 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001078 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 x1 = NULL;
1080 err = -EEXIST;
1081 goto out;
1082 }
1083
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001084 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001086 if (x1 && ((x1->id.proto != x->id.proto) ||
1087 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001088 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 x1 = NULL;
1090 }
1091 }
1092
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001093 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001094 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1095 x->id.proto,
1096 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
David S. Millerc7f5ea32006-08-24 03:29:04 -07001098 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 __xfrm_state_insert(x);
1100 err = 0;
1101
1102out:
1103 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 if (x1) {
1106 xfrm_state_delete(x1);
1107 xfrm_state_put(x1);
1108 }
1109
David S. Miller37b08e32008-09-02 20:14:15 -07001110 if (to_put)
1111 xfrm_state_put(to_put);
1112
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return err;
1114}
1115EXPORT_SYMBOL(xfrm_state_add);
1116
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001117#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001118static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001119{
1120 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001121 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001122 if (!x)
1123 goto error;
1124
1125 memcpy(&x->id, &orig->id, sizeof(x->id));
1126 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1127 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1128 x->props.mode = orig->props.mode;
1129 x->props.replay_window = orig->props.replay_window;
1130 x->props.reqid = orig->props.reqid;
1131 x->props.family = orig->props.family;
1132 x->props.saddr = orig->props.saddr;
1133
1134 if (orig->aalg) {
1135 x->aalg = xfrm_algo_clone(orig->aalg);
1136 if (!x->aalg)
1137 goto error;
1138 }
1139 x->props.aalgo = orig->props.aalgo;
1140
1141 if (orig->ealg) {
1142 x->ealg = xfrm_algo_clone(orig->ealg);
1143 if (!x->ealg)
1144 goto error;
1145 }
1146 x->props.ealgo = orig->props.ealgo;
1147
1148 if (orig->calg) {
1149 x->calg = xfrm_algo_clone(orig->calg);
1150 if (!x->calg)
1151 goto error;
1152 }
1153 x->props.calgo = orig->props.calgo;
1154
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001155 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001156 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1157 if (!x->encap)
1158 goto error;
1159 }
1160
1161 if (orig->coaddr) {
1162 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1163 GFP_KERNEL);
1164 if (!x->coaddr)
1165 goto error;
1166 }
1167
1168 err = xfrm_init_state(x);
1169 if (err)
1170 goto error;
1171
1172 x->props.flags = orig->props.flags;
1173
1174 x->curlft.add_time = orig->curlft.add_time;
1175 x->km.state = orig->km.state;
1176 x->km.seq = orig->km.seq;
1177
1178 return x;
1179
1180 error:
1181 if (errp)
1182 *errp = err;
1183 if (x) {
1184 kfree(x->aalg);
1185 kfree(x->ealg);
1186 kfree(x->calg);
1187 kfree(x->encap);
1188 kfree(x->coaddr);
1189 }
1190 kfree(x);
1191 return NULL;
1192}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001193
1194/* xfrm_state_lock is held */
1195struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1196{
1197 unsigned int h;
1198 struct xfrm_state *x;
1199 struct hlist_node *entry;
1200
1201 if (m->reqid) {
1202 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1203 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001204 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001205 if (x->props.mode != m->mode ||
1206 x->id.proto != m->proto)
1207 continue;
1208 if (m->reqid && x->props.reqid != m->reqid)
1209 continue;
1210 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1211 m->old_family) ||
1212 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1213 m->old_family))
1214 continue;
1215 xfrm_state_hold(x);
1216 return x;
1217 }
1218 } else {
1219 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1220 m->old_family);
1221 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
1222 if (x->props.mode != m->mode ||
1223 x->id.proto != m->proto)
1224 continue;
1225 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1226 m->old_family) ||
1227 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1228 m->old_family))
1229 continue;
1230 xfrm_state_hold(x);
1231 return x;
1232 }
1233 }
1234
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001235 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001236}
1237EXPORT_SYMBOL(xfrm_migrate_state_find);
1238
1239struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1240 struct xfrm_migrate *m)
1241{
1242 struct xfrm_state *xc;
1243 int err;
1244
1245 xc = xfrm_state_clone(x, &err);
1246 if (!xc)
1247 return NULL;
1248
1249 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1250 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1251
1252 /* add state */
1253 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1254 /* a care is needed when the destination address of the
1255 state is to be updated as it is a part of triplet */
1256 xfrm_state_insert(xc);
1257 } else {
1258 if ((err = xfrm_state_add(xc)) < 0)
1259 goto error;
1260 }
1261
1262 return xc;
1263error:
1264 kfree(xc);
1265 return NULL;
1266}
1267EXPORT_SYMBOL(xfrm_state_migrate);
1268#endif
1269
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270int xfrm_state_update(struct xfrm_state *x)
1271{
David S. Miller37b08e32008-09-02 20:14:15 -07001272 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001274 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
David S. Miller37b08e32008-09-02 20:14:15 -07001276 to_put = NULL;
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001279 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 err = -ESRCH;
1282 if (!x1)
1283 goto out;
1284
1285 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001286 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 err = -EEXIST;
1288 goto out;
1289 }
1290
1291 if (x1->km.state == XFRM_STATE_ACQ) {
1292 __xfrm_state_insert(x);
1293 x = NULL;
1294 }
1295 err = 0;
1296
1297out:
1298 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
David S. Miller37b08e32008-09-02 20:14:15 -07001300 if (to_put)
1301 xfrm_state_put(to_put);
1302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (err)
1304 return err;
1305
1306 if (!x) {
1307 xfrm_state_delete(x1);
1308 xfrm_state_put(x1);
1309 return 0;
1310 }
1311
1312 err = -EINVAL;
1313 spin_lock_bh(&x1->lock);
1314 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1315 if (x->encap && x1->encap)
1316 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001317 if (x->coaddr && x1->coaddr) {
1318 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1319 }
1320 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1321 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1323 x1->km.dying = 0;
1324
David S. Millera47f0ce2006-08-24 03:54:22 -07001325 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (x1->curlft.use_time)
1327 xfrm_state_check_expire(x1);
1328
1329 err = 0;
1330 }
1331 spin_unlock_bh(&x1->lock);
1332
1333 xfrm_state_put(x1);
1334
1335 return err;
1336}
1337EXPORT_SYMBOL(xfrm_state_update);
1338
1339int xfrm_state_check_expire(struct xfrm_state *x)
1340{
1341 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001342 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 if (x->km.state != XFRM_STATE_VALID)
1345 return -EINVAL;
1346
1347 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1348 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001349 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001350 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return -EINVAL;
1352 }
1353
1354 if (!x->km.dying &&
1355 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001356 x->curlft.packets >= x->lft.soft_packet_limit)) {
1357 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001358 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return 0;
1361}
1362EXPORT_SYMBOL(xfrm_state_check_expire);
1363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001365xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 unsigned short family)
1367{
1368 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001371 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 return x;
1374}
1375EXPORT_SYMBOL(xfrm_state_lookup);
1376
1377struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001378xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1379 u8 proto, unsigned short family)
1380{
1381 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001382
1383 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001384 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001385 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001386 return x;
1387}
1388EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1389
1390struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001391xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1392 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 int create, unsigned short family)
1394{
1395 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
1397 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001398 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 return x;
1402}
1403EXPORT_SYMBOL(xfrm_find_acq);
1404
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001405#ifdef CONFIG_XFRM_SUB_POLICY
1406int
1407xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1408 unsigned short family)
1409{
1410 int err = 0;
1411 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1412 if (!afinfo)
1413 return -EAFNOSUPPORT;
1414
1415 spin_lock_bh(&xfrm_state_lock);
1416 if (afinfo->tmpl_sort)
1417 err = afinfo->tmpl_sort(dst, src, n);
1418 spin_unlock_bh(&xfrm_state_lock);
1419 xfrm_state_put_afinfo(afinfo);
1420 return err;
1421}
1422EXPORT_SYMBOL(xfrm_tmpl_sort);
1423
1424int
1425xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1426 unsigned short family)
1427{
1428 int err = 0;
1429 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1430 if (!afinfo)
1431 return -EAFNOSUPPORT;
1432
1433 spin_lock_bh(&xfrm_state_lock);
1434 if (afinfo->state_sort)
1435 err = afinfo->state_sort(dst, src, n);
1436 spin_unlock_bh(&xfrm_state_lock);
1437 xfrm_state_put_afinfo(afinfo);
1438 return err;
1439}
1440EXPORT_SYMBOL(xfrm_state_sort);
1441#endif
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443/* Silly enough, but I'm lazy to build resolution list */
1444
1445static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1446{
1447 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
David S. Millerf034b5d2006-08-24 03:08:07 -07001449 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001450 struct hlist_node *entry;
1451 struct xfrm_state *x;
1452
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001453 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001454 if (x->km.seq == seq &&
1455 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 xfrm_state_hold(x);
1457 return x;
1458 }
1459 }
1460 }
1461 return NULL;
1462}
1463
1464struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1465{
1466 struct xfrm_state *x;
1467
1468 spin_lock_bh(&xfrm_state_lock);
1469 x = __xfrm_find_acq_byseq(seq);
1470 spin_unlock_bh(&xfrm_state_lock);
1471 return x;
1472}
1473EXPORT_SYMBOL(xfrm_find_acq_byseq);
1474
1475u32 xfrm_get_acqseq(void)
1476{
1477 u32 res;
1478 static u32 acqseq;
1479 static DEFINE_SPINLOCK(acqseq_lock);
1480
1481 spin_lock_bh(&acqseq_lock);
1482 res = (++acqseq ? : ++acqseq);
1483 spin_unlock_bh(&acqseq_lock);
1484 return res;
1485}
1486EXPORT_SYMBOL(xfrm_get_acqseq);
1487
Herbert Xu658b2192007-10-09 13:29:52 -07001488int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489{
David S. Millerf034b5d2006-08-24 03:08:07 -07001490 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001492 int err = -ENOENT;
1493 __be32 minspi = htonl(low);
1494 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Herbert Xu658b2192007-10-09 13:29:52 -07001496 spin_lock_bh(&x->lock);
1497 if (x->km.state == XFRM_STATE_DEAD)
1498 goto unlock;
1499
1500 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001502 goto unlock;
1503
1504 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
1506 if (minspi == maxspi) {
1507 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1508 if (x0) {
1509 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001510 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 }
1512 x->id.spi = minspi;
1513 } else {
1514 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001515 for (h=0; h<high-low+1; h++) {
1516 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1518 if (x0 == NULL) {
1519 x->id.spi = htonl(spi);
1520 break;
1521 }
1522 xfrm_state_put(x0);
1523 }
1524 }
1525 if (x->id.spi) {
1526 spin_lock_bh(&xfrm_state_lock);
1527 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -07001528 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001530
1531 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 }
Herbert Xu658b2192007-10-09 13:29:52 -07001533
1534unlock:
1535 spin_unlock_bh(&x->lock);
1536
1537 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538}
1539EXPORT_SYMBOL(xfrm_alloc_spi);
1540
Timo Teras4c563f72008-02-28 21:31:08 -08001541int xfrm_state_walk(struct xfrm_state_walk *walk,
1542 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 void *data)
1544{
Herbert Xu12a169e2008-10-01 07:03:24 -07001545 struct xfrm_state *state;
1546 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 int err = 0;
1548
Herbert Xu12a169e2008-10-01 07:03:24 -07001549 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001550 return 0;
1551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001553 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001554 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001555 else
1556 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001557 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001558 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001559 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001560 state = container_of(x, struct xfrm_state, km);
1561 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001562 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001563 err = func(state, walk->seq, data);
1564 if (err) {
1565 list_move_tail(&walk->all, &x->all);
1566 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001568 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001570 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 err = -ENOENT;
1572 goto out;
1573 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001574 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575out:
1576 spin_unlock_bh(&xfrm_state_lock);
1577 return err;
1578}
1579EXPORT_SYMBOL(xfrm_state_walk);
1580
Herbert Xu5c182452008-09-22 19:48:19 -07001581void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1582{
Herbert Xu12a169e2008-10-01 07:03:24 -07001583 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001584 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001585 walk->state = XFRM_STATE_DEAD;
1586 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001587}
1588EXPORT_SYMBOL(xfrm_state_walk_init);
1589
Herbert Xuabb81c42008-09-09 19:58:29 -07001590void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1591{
Herbert Xu12a169e2008-10-01 07:03:24 -07001592 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001593 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001594
Herbert Xu12a169e2008-10-01 07:03:24 -07001595 spin_lock_bh(&xfrm_state_lock);
1596 list_del(&walk->all);
1597 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001598}
1599EXPORT_SYMBOL(xfrm_state_walk_done);
1600
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001601
1602void xfrm_replay_notify(struct xfrm_state *x, int event)
1603{
1604 struct km_event c;
1605 /* we send notify messages in case
1606 * 1. we updated on of the sequence numbers, and the seqno difference
1607 * is at least x->replay_maxdiff, in this case we also update the
1608 * timeout of our timer function
1609 * 2. if x->replay_maxage has elapsed since last update,
1610 * and there were changes
1611 *
1612 * The state structure must be locked!
1613 */
1614
1615 switch (event) {
1616 case XFRM_REPLAY_UPDATE:
1617 if (x->replay_maxdiff &&
1618 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001619 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1620 if (x->xflags & XFRM_TIME_DEFER)
1621 event = XFRM_REPLAY_TIMEOUT;
1622 else
1623 return;
1624 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001625
1626 break;
1627
1628 case XFRM_REPLAY_TIMEOUT:
1629 if ((x->replay.seq == x->preplay.seq) &&
1630 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001631 (x->replay.oseq == x->preplay.oseq)) {
1632 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001633 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001634 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001635
1636 break;
1637 }
1638
1639 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1640 c.event = XFRM_MSG_NEWAE;
1641 c.data.aevent = event;
1642 km_state_notify(x, &c);
1643
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001644 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001645 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001646 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001647}
1648
1649static void xfrm_replay_timer_handler(unsigned long data)
1650{
1651 struct xfrm_state *x = (struct xfrm_state*)data;
1652
1653 spin_lock(&x->lock);
1654
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001655 if (x->km.state == XFRM_STATE_VALID) {
1656 if (xfrm_aevent_is_on())
1657 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1658 else
1659 x->xflags |= XFRM_TIME_DEFER;
1660 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001661
1662 spin_unlock(&x->lock);
1663}
1664
Paul Mooreafeb14b2007-12-21 14:58:11 -08001665int xfrm_replay_check(struct xfrm_state *x,
1666 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667{
1668 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001669 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001672 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 if (likely(seq > x->replay.seq))
1675 return 0;
1676
1677 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001678 if (diff >= min_t(unsigned int, x->props.replay_window,
1679 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001681 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 }
1683
1684 if (x->replay.bitmap & (1U << diff)) {
1685 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001686 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 }
1688 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001689
1690err:
1691 xfrm_audit_state_replay(x, skb, net_seq);
1692 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
Al Viro61f46272006-09-27 18:48:33 -07001695void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696{
1697 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001698 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 if (seq > x->replay.seq) {
1701 diff = seq - x->replay.seq;
1702 if (diff < x->props.replay_window)
1703 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1704 else
1705 x->replay.bitmap = 1;
1706 x->replay.seq = seq;
1707 } else {
1708 diff = x->replay.seq - seq;
1709 x->replay.bitmap |= (1U << diff);
1710 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001711
1712 if (xfrm_aevent_is_on())
1713 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
Denis Chengdf018122007-12-07 00:51:11 -08001716static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717static DEFINE_RWLOCK(xfrm_km_lock);
1718
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001719void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 struct xfrm_mgr *km;
1722
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001723 read_lock(&xfrm_km_lock);
1724 list_for_each_entry(km, &xfrm_km_list, list)
1725 if (km->notify_policy)
1726 km->notify_policy(xp, dir, c);
1727 read_unlock(&xfrm_km_lock);
1728}
1729
1730void km_state_notify(struct xfrm_state *x, struct km_event *c)
1731{
1732 struct xfrm_mgr *km;
1733 read_lock(&xfrm_km_lock);
1734 list_for_each_entry(km, &xfrm_km_list, list)
1735 if (km->notify)
1736 km->notify(x, c);
1737 read_unlock(&xfrm_km_lock);
1738}
1739
1740EXPORT_SYMBOL(km_policy_notify);
1741EXPORT_SYMBOL(km_state_notify);
1742
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001743void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001744{
1745 struct km_event c;
1746
Herbert Xubf088672005-06-18 22:44:00 -07001747 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001748 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001749 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001750 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 if (hard)
1753 wake_up(&km_waitq);
1754}
1755
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001756EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001757/*
1758 * We send to all registered managers regardless of failure
1759 * We are happy with one success
1760*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001761int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001763 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 struct xfrm_mgr *km;
1765
1766 read_lock(&xfrm_km_lock);
1767 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001768 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1769 if (!acqret)
1770 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
1772 read_unlock(&xfrm_km_lock);
1773 return err;
1774}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001775EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Al Viro5d36b182006-11-08 00:24:06 -08001777int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778{
1779 int err = -EINVAL;
1780 struct xfrm_mgr *km;
1781
1782 read_lock(&xfrm_km_lock);
1783 list_for_each_entry(km, &xfrm_km_list, list) {
1784 if (km->new_mapping)
1785 err = km->new_mapping(x, ipaddr, sport);
1786 if (!err)
1787 break;
1788 }
1789 read_unlock(&xfrm_km_lock);
1790 return err;
1791}
1792EXPORT_SYMBOL(km_new_mapping);
1793
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001794void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001796 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Herbert Xubf088672005-06-18 22:44:00 -07001798 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001799 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001800 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001801 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803 if (hard)
1804 wake_up(&km_waitq);
1805}
David S. Millera70fcb02006-03-20 19:18:52 -08001806EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001808#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001809int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001810 struct xfrm_migrate *m, int num_migrate,
1811 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001812{
1813 int err = -EINVAL;
1814 int ret;
1815 struct xfrm_mgr *km;
1816
1817 read_lock(&xfrm_km_lock);
1818 list_for_each_entry(km, &xfrm_km_list, list) {
1819 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001820 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001821 if (!ret)
1822 err = ret;
1823 }
1824 }
1825 read_unlock(&xfrm_km_lock);
1826 return err;
1827}
1828EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001829#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001830
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001831int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1832{
1833 int err = -EINVAL;
1834 int ret;
1835 struct xfrm_mgr *km;
1836
1837 read_lock(&xfrm_km_lock);
1838 list_for_each_entry(km, &xfrm_km_list, list) {
1839 if (km->report) {
1840 ret = km->report(proto, sel, addr);
1841 if (!ret)
1842 err = ret;
1843 }
1844 }
1845 read_unlock(&xfrm_km_lock);
1846 return err;
1847}
1848EXPORT_SYMBOL(km_report);
1849
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1851{
1852 int err;
1853 u8 *data;
1854 struct xfrm_mgr *km;
1855 struct xfrm_policy *pol = NULL;
1856
1857 if (optlen <= 0 || optlen > PAGE_SIZE)
1858 return -EMSGSIZE;
1859
1860 data = kmalloc(optlen, GFP_KERNEL);
1861 if (!data)
1862 return -ENOMEM;
1863
1864 err = -EFAULT;
1865 if (copy_from_user(data, optval, optlen))
1866 goto out;
1867
1868 err = -EINVAL;
1869 read_lock(&xfrm_km_lock);
1870 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001871 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 optlen, &err);
1873 if (err >= 0)
1874 break;
1875 }
1876 read_unlock(&xfrm_km_lock);
1877
1878 if (err >= 0) {
1879 xfrm_sk_policy_insert(sk, err, pol);
1880 xfrm_pol_put(pol);
1881 err = 0;
1882 }
1883
1884out:
1885 kfree(data);
1886 return err;
1887}
1888EXPORT_SYMBOL(xfrm_user_policy);
1889
1890int xfrm_register_km(struct xfrm_mgr *km)
1891{
1892 write_lock_bh(&xfrm_km_lock);
1893 list_add_tail(&km->list, &xfrm_km_list);
1894 write_unlock_bh(&xfrm_km_lock);
1895 return 0;
1896}
1897EXPORT_SYMBOL(xfrm_register_km);
1898
1899int xfrm_unregister_km(struct xfrm_mgr *km)
1900{
1901 write_lock_bh(&xfrm_km_lock);
1902 list_del(&km->list);
1903 write_unlock_bh(&xfrm_km_lock);
1904 return 0;
1905}
1906EXPORT_SYMBOL(xfrm_unregister_km);
1907
1908int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1909{
1910 int err = 0;
1911 if (unlikely(afinfo == NULL))
1912 return -EINVAL;
1913 if (unlikely(afinfo->family >= NPROTO))
1914 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001915 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1917 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001918 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001920 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 return err;
1922}
1923EXPORT_SYMBOL(xfrm_state_register_afinfo);
1924
1925int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1926{
1927 int err = 0;
1928 if (unlikely(afinfo == NULL))
1929 return -EINVAL;
1930 if (unlikely(afinfo->family >= NPROTO))
1931 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001932 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1934 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1935 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001936 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001939 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 return err;
1941}
1942EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1943
Herbert Xu17c2a422007-10-17 21:33:12 -07001944static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945{
1946 struct xfrm_state_afinfo *afinfo;
1947 if (unlikely(family >= NPROTO))
1948 return NULL;
1949 read_lock(&xfrm_state_afinfo_lock);
1950 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001951 if (unlikely(!afinfo))
1952 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 return afinfo;
1954}
1955
Herbert Xu17c2a422007-10-17 21:33:12 -07001956static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001957 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958{
Herbert Xu546be242006-05-27 23:03:58 -07001959 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960}
1961
1962/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1963void xfrm_state_delete_tunnel(struct xfrm_state *x)
1964{
1965 if (x->tunnel) {
1966 struct xfrm_state *t = x->tunnel;
1967
1968 if (atomic_read(&t->tunnel_users) == 2)
1969 xfrm_state_delete(t);
1970 atomic_dec(&t->tunnel_users);
1971 xfrm_state_put(t);
1972 x->tunnel = NULL;
1973 }
1974}
1975EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1976
1977int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1978{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001979 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Patrick McHardyc5c25232007-04-09 11:47:18 -07001981 spin_lock_bh(&x->lock);
1982 if (x->km.state == XFRM_STATE_VALID &&
1983 x->type && x->type->get_mtu)
1984 res = x->type->get_mtu(x, mtu);
1985 else
Patrick McHardy28121612007-06-18 22:30:15 -07001986 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001987 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 return res;
1989}
1990
Herbert Xu72cb6962005-06-20 13:18:08 -07001991int xfrm_init_state(struct xfrm_state *x)
1992{
Herbert Xud094cd82005-06-20 13:19:41 -07001993 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001994 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001995 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001996 int err;
1997
Herbert Xud094cd82005-06-20 13:19:41 -07001998 err = -EAFNOSUPPORT;
1999 afinfo = xfrm_state_get_afinfo(family);
2000 if (!afinfo)
2001 goto error;
2002
2003 err = 0;
2004 if (afinfo->init_flags)
2005 err = afinfo->init_flags(x);
2006
2007 xfrm_state_put_afinfo(afinfo);
2008
2009 if (err)
2010 goto error;
2011
2012 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002013
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002014 if (x->sel.family != AF_UNSPEC) {
2015 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2016 if (inner_mode == NULL)
2017 goto error;
2018
2019 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2020 family != x->sel.family) {
2021 xfrm_put_mode(inner_mode);
2022 goto error;
2023 }
2024
2025 x->inner_mode = inner_mode;
2026 } else {
2027 struct xfrm_mode *inner_mode_iaf;
2028
2029 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2030 if (inner_mode == NULL)
2031 goto error;
2032
2033 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2034 xfrm_put_mode(inner_mode);
2035 goto error;
2036 }
2037
2038 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2039 if (inner_mode_iaf == NULL)
2040 goto error;
2041
2042 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2043 xfrm_put_mode(inner_mode_iaf);
2044 goto error;
2045 }
2046
2047 if (x->props.family == AF_INET) {
2048 x->inner_mode = inner_mode;
2049 x->inner_mode_iaf = inner_mode_iaf;
2050 } else {
2051 x->inner_mode = inner_mode_iaf;
2052 x->inner_mode_iaf = inner_mode;
2053 }
2054 }
Herbert Xu13996372007-10-17 21:35:51 -07002055
Herbert Xud094cd82005-06-20 13:19:41 -07002056 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002057 if (x->type == NULL)
2058 goto error;
2059
2060 err = x->type->init_state(x);
2061 if (err)
2062 goto error;
2063
Herbert Xu13996372007-10-17 21:35:51 -07002064 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2065 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002066 goto error;
2067
Herbert Xu72cb6962005-06-20 13:18:08 -07002068 x->km.state = XFRM_STATE_VALID;
2069
2070error:
2071 return err;
2072}
2073
2074EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002075
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002076int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
David S. Millerf034b5d2006-08-24 03:08:07 -07002078 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002080 INIT_LIST_HEAD(&net->xfrm.state_all);
2081
David S. Millerf034b5d2006-08-24 03:08:07 -07002082 sz = sizeof(struct hlist_head) * 8;
2083
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002084 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2085 if (!net->xfrm.state_bydst)
2086 goto out_bydst;
David S. Miller44e36b42006-08-24 04:50:50 -07002087 xfrm_state_bysrc = xfrm_hash_alloc(sz);
2088 xfrm_state_byspi = xfrm_hash_alloc(sz);
David S. Millerf034b5d2006-08-24 03:08:07 -07002089 xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
2090
David Howellsc4028952006-11-22 14:57:56 +00002091 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002092 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002093
2094out_bydst:
2095 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002096}
2097
2098void xfrm_state_fini(struct net *net)
2099{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002100 unsigned int sz;
2101
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002102 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002103
2104 sz = (xfrm_state_hmask + 1) * sizeof(struct hlist_head);
2105 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2106 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107}
2108
Joy Lattenab5f5e82007-09-17 11:51:22 -07002109#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002110static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2111 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002112{
Paul Moore68277ac2007-12-20 20:49:33 -08002113 struct xfrm_sec_ctx *ctx = x->security;
2114 u32 spi = ntohl(x->id.spi);
2115
2116 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002117 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002118 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002119
2120 switch(x->props.family) {
2121 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002122 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2123 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002124 break;
2125 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002126 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002127 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002128 break;
2129 }
Paul Moore68277ac2007-12-20 20:49:33 -08002130
2131 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002132}
2133
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002134static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2135 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002136{
2137 struct iphdr *iph4;
2138 struct ipv6hdr *iph6;
2139
2140 switch (family) {
2141 case AF_INET:
2142 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002143 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2144 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002145 break;
2146 case AF_INET6:
2147 iph6 = ipv6_hdr(skb);
2148 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002149 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002150 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002151 iph6->flow_lbl[0] & 0x0f,
2152 iph6->flow_lbl[1],
2153 iph6->flow_lbl[2]);
2154 break;
2155 }
2156}
2157
Paul Moore68277ac2007-12-20 20:49:33 -08002158void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002159 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002160{
2161 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002162
Paul Mooreafeb14b2007-12-21 14:58:11 -08002163 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002164 if (audit_buf == NULL)
2165 return;
Eric Paris25323862008-04-18 10:09:25 -04002166 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002167 xfrm_audit_helper_sainfo(x, audit_buf);
2168 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002169 audit_log_end(audit_buf);
2170}
2171EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2172
Paul Moore68277ac2007-12-20 20:49:33 -08002173void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002174 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002175{
2176 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002177
Paul Mooreafeb14b2007-12-21 14:58:11 -08002178 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002179 if (audit_buf == NULL)
2180 return;
Eric Paris25323862008-04-18 10:09:25 -04002181 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002182 xfrm_audit_helper_sainfo(x, audit_buf);
2183 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002184 audit_log_end(audit_buf);
2185}
2186EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002187
2188void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2189 struct sk_buff *skb)
2190{
2191 struct audit_buffer *audit_buf;
2192 u32 spi;
2193
2194 audit_buf = xfrm_audit_start("SA-replay-overflow");
2195 if (audit_buf == NULL)
2196 return;
2197 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2198 /* don't record the sequence number because it's inherent in this kind
2199 * of audit message */
2200 spi = ntohl(x->id.spi);
2201 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2202 audit_log_end(audit_buf);
2203}
2204EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2205
2206static void xfrm_audit_state_replay(struct xfrm_state *x,
2207 struct sk_buff *skb, __be32 net_seq)
2208{
2209 struct audit_buffer *audit_buf;
2210 u32 spi;
2211
2212 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2213 if (audit_buf == NULL)
2214 return;
2215 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2216 spi = ntohl(x->id.spi);
2217 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2218 spi, spi, ntohl(net_seq));
2219 audit_log_end(audit_buf);
2220}
2221
2222void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2223{
2224 struct audit_buffer *audit_buf;
2225
2226 audit_buf = xfrm_audit_start("SA-notfound");
2227 if (audit_buf == NULL)
2228 return;
2229 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2230 audit_log_end(audit_buf);
2231}
2232EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2233
2234void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2235 __be32 net_spi, __be32 net_seq)
2236{
2237 struct audit_buffer *audit_buf;
2238 u32 spi;
2239
2240 audit_buf = xfrm_audit_start("SA-notfound");
2241 if (audit_buf == NULL)
2242 return;
2243 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2244 spi = ntohl(net_spi);
2245 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2246 spi, spi, ntohl(net_seq));
2247 audit_log_end(audit_buf);
2248}
2249EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2250
2251void xfrm_audit_state_icvfail(struct xfrm_state *x,
2252 struct sk_buff *skb, u8 proto)
2253{
2254 struct audit_buffer *audit_buf;
2255 __be32 net_spi;
2256 __be32 net_seq;
2257
2258 audit_buf = xfrm_audit_start("SA-icv-failure");
2259 if (audit_buf == NULL)
2260 return;
2261 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2262 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2263 u32 spi = ntohl(net_spi);
2264 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2265 spi, spi, ntohl(net_seq));
2266 }
2267 audit_log_end(audit_buf);
2268}
2269EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002270#endif /* CONFIG_AUDITSYSCALL */