blob: 52d828bdf3d7244ab2cd5703d46864f00c5c0417 [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_byspi __read_mostly;
48static unsigned int xfrm_state_hmask __read_mostly;
49static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
50static unsigned int xfrm_state_num;
David S. Miller9d4a7062006-08-24 03:18:09 -070051static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Herbert Xu17c2a422007-10-17 21:33:12 -070053static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
54static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
55
Paul Mooreafeb14b2007-12-21 14:58:11 -080056#ifdef CONFIG_AUDITSYSCALL
57static void xfrm_audit_state_replay(struct xfrm_state *x,
58 struct sk_buff *skb, __be32 net_seq);
59#else
60#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
61#endif /* CONFIG_AUDITSYSCALL */
62
David S. Millerc1969f22006-08-24 04:00:03 -070063static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
64 xfrm_address_t *saddr,
65 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070066 unsigned short family)
67{
David S. Millerc1969f22006-08-24 04:00:03 -070068 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070069}
70
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070071static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
72 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070073 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070074{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070075 return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070076}
77
David S. Miller2575b652006-08-24 03:26:44 -070078static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070079xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070080{
David S. Millerc1969f22006-08-24 04:00:03 -070081 return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070082}
83
David S. Millerf034b5d2006-08-24 03:08:07 -070084static void xfrm_hash_transfer(struct hlist_head *list,
85 struct hlist_head *ndsttable,
86 struct hlist_head *nsrctable,
87 struct hlist_head *nspitable,
88 unsigned int nhashmask)
89{
90 struct hlist_node *entry, *tmp;
91 struct xfrm_state *x;
92
93 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
94 unsigned int h;
95
David S. Millerc1969f22006-08-24 04:00:03 -070096 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
97 x->props.reqid, x->props.family,
98 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070099 hlist_add_head(&x->bydst, ndsttable+h);
100
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700101 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
102 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700103 nhashmask);
104 hlist_add_head(&x->bysrc, nsrctable+h);
105
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700106 if (x->id.spi) {
107 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
108 x->id.proto, x->props.family,
109 nhashmask);
110 hlist_add_head(&x->byspi, nspitable+h);
111 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700112 }
113}
114
115static unsigned long xfrm_hash_new_size(void)
116{
117 return ((xfrm_state_hmask + 1) << 1) *
118 sizeof(struct hlist_head);
119}
120
121static DEFINE_MUTEX(hash_resize_mutex);
122
David Howellsc4028952006-11-22 14:57:56 +0000123static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700124{
125 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
126 unsigned long nsize, osize;
127 unsigned int nhashmask, ohashmask;
128 int i;
129
130 mutex_lock(&hash_resize_mutex);
131
132 nsize = xfrm_hash_new_size();
David S. Miller44e36b42006-08-24 04:50:50 -0700133 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700134 if (!ndst)
135 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700136 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700137 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700138 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700139 goto out_unlock;
140 }
David S. Miller44e36b42006-08-24 04:50:50 -0700141 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700142 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700143 xfrm_hash_free(ndst, nsize);
144 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700145 goto out_unlock;
146 }
147
148 spin_lock_bh(&xfrm_state_lock);
149
150 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
151 for (i = xfrm_state_hmask; i >= 0; i--)
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800152 xfrm_hash_transfer(init_net.xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700153 nhashmask);
154
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800155 odst = init_net.xfrm.state_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800156 osrc = init_net.xfrm.state_bysrc;
David S. Millerf034b5d2006-08-24 03:08:07 -0700157 ospi = xfrm_state_byspi;
158 ohashmask = xfrm_state_hmask;
159
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800160 init_net.xfrm.state_bydst = ndst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800161 init_net.xfrm.state_bysrc = nsrc;
David S. Millerf034b5d2006-08-24 03:08:07 -0700162 xfrm_state_byspi = nspi;
163 xfrm_state_hmask = nhashmask;
164
165 spin_unlock_bh(&xfrm_state_lock);
166
167 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700168 xfrm_hash_free(odst, osize);
169 xfrm_hash_free(osrc, osize);
170 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700171
172out_unlock:
173 mutex_unlock(&hash_resize_mutex);
174}
175
David Howellsc4028952006-11-22 14:57:56 +0000176static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178DECLARE_WAIT_QUEUE_HEAD(km_waitq);
179EXPORT_SYMBOL(km_waitq);
180
181static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
182static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
183
184static struct work_struct xfrm_state_gc_work;
Herbert Xu12a169e2008-10-01 07:03:24 -0700185static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static DEFINE_SPINLOCK(xfrm_state_gc_lock);
187
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800188int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800190int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800191void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700193static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
194{
195 struct xfrm_state_afinfo *afinfo;
196 if (unlikely(family >= NPROTO))
197 return NULL;
198 write_lock_bh(&xfrm_state_afinfo_lock);
199 afinfo = xfrm_state_afinfo[family];
200 if (unlikely(!afinfo))
201 write_unlock_bh(&xfrm_state_afinfo_lock);
202 return afinfo;
203}
204
205static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800206 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700207{
208 write_unlock_bh(&xfrm_state_afinfo_lock);
209}
210
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800211int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700212{
213 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800214 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700215 int err = 0;
216
217 if (unlikely(afinfo == NULL))
218 return -EAFNOSUPPORT;
219 typemap = afinfo->type_map;
220
221 if (likely(typemap[type->proto] == NULL))
222 typemap[type->proto] = type;
223 else
224 err = -EEXIST;
225 xfrm_state_unlock_afinfo(afinfo);
226 return err;
227}
228EXPORT_SYMBOL(xfrm_register_type);
229
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800230int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700231{
232 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800233 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700234 int err = 0;
235
236 if (unlikely(afinfo == NULL))
237 return -EAFNOSUPPORT;
238 typemap = afinfo->type_map;
239
240 if (unlikely(typemap[type->proto] != type))
241 err = -ENOENT;
242 else
243 typemap[type->proto] = NULL;
244 xfrm_state_unlock_afinfo(afinfo);
245 return err;
246}
247EXPORT_SYMBOL(xfrm_unregister_type);
248
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800249static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700250{
251 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800252 const struct xfrm_type **typemap;
253 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700254 int modload_attempted = 0;
255
256retry:
257 afinfo = xfrm_state_get_afinfo(family);
258 if (unlikely(afinfo == NULL))
259 return NULL;
260 typemap = afinfo->type_map;
261
262 type = typemap[proto];
263 if (unlikely(type && !try_module_get(type->owner)))
264 type = NULL;
265 if (!type && !modload_attempted) {
266 xfrm_state_put_afinfo(afinfo);
267 request_module("xfrm-type-%d-%d", family, proto);
268 modload_attempted = 1;
269 goto retry;
270 }
271
272 xfrm_state_put_afinfo(afinfo);
273 return type;
274}
275
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800276static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700277{
278 module_put(type->owner);
279}
280
281int xfrm_register_mode(struct xfrm_mode *mode, int family)
282{
283 struct xfrm_state_afinfo *afinfo;
284 struct xfrm_mode **modemap;
285 int err;
286
287 if (unlikely(mode->encap >= XFRM_MODE_MAX))
288 return -EINVAL;
289
290 afinfo = xfrm_state_lock_afinfo(family);
291 if (unlikely(afinfo == NULL))
292 return -EAFNOSUPPORT;
293
294 err = -EEXIST;
295 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700296 if (modemap[mode->encap])
297 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700298
Herbert Xu17c2a422007-10-17 21:33:12 -0700299 err = -ENOENT;
300 if (!try_module_get(afinfo->owner))
301 goto out;
302
303 mode->afinfo = afinfo;
304 modemap[mode->encap] = mode;
305 err = 0;
306
307out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700308 xfrm_state_unlock_afinfo(afinfo);
309 return err;
310}
311EXPORT_SYMBOL(xfrm_register_mode);
312
313int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
314{
315 struct xfrm_state_afinfo *afinfo;
316 struct xfrm_mode **modemap;
317 int err;
318
319 if (unlikely(mode->encap >= XFRM_MODE_MAX))
320 return -EINVAL;
321
322 afinfo = xfrm_state_lock_afinfo(family);
323 if (unlikely(afinfo == NULL))
324 return -EAFNOSUPPORT;
325
326 err = -ENOENT;
327 modemap = afinfo->mode_map;
328 if (likely(modemap[mode->encap] == mode)) {
329 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700330 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700331 err = 0;
332 }
333
334 xfrm_state_unlock_afinfo(afinfo);
335 return err;
336}
337EXPORT_SYMBOL(xfrm_unregister_mode);
338
339static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
340{
341 struct xfrm_state_afinfo *afinfo;
342 struct xfrm_mode *mode;
343 int modload_attempted = 0;
344
345 if (unlikely(encap >= XFRM_MODE_MAX))
346 return NULL;
347
348retry:
349 afinfo = xfrm_state_get_afinfo(family);
350 if (unlikely(afinfo == NULL))
351 return NULL;
352
353 mode = afinfo->mode_map[encap];
354 if (unlikely(mode && !try_module_get(mode->owner)))
355 mode = NULL;
356 if (!mode && !modload_attempted) {
357 xfrm_state_put_afinfo(afinfo);
358 request_module("xfrm-mode-%d-%d", family, encap);
359 modload_attempted = 1;
360 goto retry;
361 }
362
363 xfrm_state_put_afinfo(afinfo);
364 return mode;
365}
366
367static void xfrm_put_mode(struct xfrm_mode *mode)
368{
369 module_put(mode->owner);
370}
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372static void xfrm_state_gc_destroy(struct xfrm_state *x)
373{
David S. Millera47f0ce2006-08-24 03:54:22 -0700374 del_timer_sync(&x->timer);
375 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800376 kfree(x->aalg);
377 kfree(x->ealg);
378 kfree(x->calg);
379 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700380 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700381 if (x->inner_mode)
382 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700383 if (x->inner_mode_iaf)
384 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700385 if (x->outer_mode)
386 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 if (x->type) {
388 x->type->destructor(x);
389 xfrm_put_type(x->type);
390 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800391 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 kfree(x);
393}
394
David Howellsc4028952006-11-22 14:57:56 +0000395static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396{
Herbert Xu12a169e2008-10-01 07:03:24 -0700397 struct xfrm_state *x;
398 struct hlist_node *entry, *tmp;
399 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700402 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 spin_unlock_bh(&xfrm_state_gc_lock);
404
Herbert Xu12a169e2008-10-01 07:03:24 -0700405 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 wake_up(&km_waitq);
409}
410
411static inline unsigned long make_jiffies(long secs)
412{
413 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
414 return MAX_SCHEDULE_TIMEOUT-1;
415 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900416 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
419static void xfrm_timer_handler(unsigned long data)
420{
421 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800422 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 long next = LONG_MAX;
424 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600425 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 spin_lock(&x->lock);
428 if (x->km.state == XFRM_STATE_DEAD)
429 goto out;
430 if (x->km.state == XFRM_STATE_EXPIRED)
431 goto expired;
432 if (x->lft.hard_add_expires_seconds) {
433 long tmo = x->lft.hard_add_expires_seconds +
434 x->curlft.add_time - now;
435 if (tmo <= 0)
436 goto expired;
437 if (tmo < next)
438 next = tmo;
439 }
440 if (x->lft.hard_use_expires_seconds) {
441 long tmo = x->lft.hard_use_expires_seconds +
442 (x->curlft.use_time ? : now) - now;
443 if (tmo <= 0)
444 goto expired;
445 if (tmo < next)
446 next = tmo;
447 }
448 if (x->km.dying)
449 goto resched;
450 if (x->lft.soft_add_expires_seconds) {
451 long tmo = x->lft.soft_add_expires_seconds +
452 x->curlft.add_time - now;
453 if (tmo <= 0)
454 warn = 1;
455 else if (tmo < next)
456 next = tmo;
457 }
458 if (x->lft.soft_use_expires_seconds) {
459 long tmo = x->lft.soft_use_expires_seconds +
460 (x->curlft.use_time ? : now) - now;
461 if (tmo <= 0)
462 warn = 1;
463 else if (tmo < next)
464 next = tmo;
465 }
466
Herbert Xu4666faa2005-06-18 22:43:22 -0700467 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800469 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700471 if (next != LONG_MAX)
472 mod_timer(&x->timer, jiffies + make_jiffies(next));
473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 goto out;
475
476expired:
477 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
478 x->km.state = XFRM_STATE_EXPIRED;
479 wake_up(&km_waitq);
480 next = 2;
481 goto resched;
482 }
Joy Latten161a09e2006-11-27 13:11:54 -0600483
484 err = __xfrm_state_delete(x);
485 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800486 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Joy Lattenab5f5e82007-09-17 11:51:22 -0700488 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400489 audit_get_loginuid(current),
490 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492out:
493 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
David S. Miller0ac84752006-03-20 19:18:23 -0800496static void xfrm_replay_timer_handler(unsigned long data);
497
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800498struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct xfrm_state *x;
501
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700502 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800505 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 atomic_set(&x->refcnt, 1);
507 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700508 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700509 INIT_HLIST_NODE(&x->bydst);
510 INIT_HLIST_NODE(&x->bysrc);
511 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800512 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
513 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
514 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800515 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 x->lft.soft_byte_limit = XFRM_INF;
517 x->lft.soft_packet_limit = XFRM_INF;
518 x->lft.hard_byte_limit = XFRM_INF;
519 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800520 x->replay_maxage = 0;
521 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700522 x->inner_mode = NULL;
523 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 spin_lock_init(&x->lock);
525 }
526 return x;
527}
528EXPORT_SYMBOL(xfrm_state_alloc);
529
530void __xfrm_state_destroy(struct xfrm_state *x)
531{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700532 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700535 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 spin_unlock_bh(&xfrm_state_gc_lock);
537 schedule_work(&xfrm_state_gc_work);
538}
539EXPORT_SYMBOL(__xfrm_state_destroy);
540
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800541int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700543 int err = -ESRCH;
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 if (x->km.state != XFRM_STATE_DEAD) {
546 x->km.state = XFRM_STATE_DEAD;
547 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700548 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700549 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700550 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700551 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700552 hlist_del(&x->byspi);
David S. Millerf034b5d2006-08-24 03:08:07 -0700553 xfrm_state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 /* All xfrm_state objects are created by xfrm_state_alloc.
557 * The xfrm_state_alloc call gives a reference, and that
558 * is what we are dropping here.
559 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800560 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700561 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700563
564 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800566EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700568int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700570 int err;
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700573 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700575
576 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578EXPORT_SYMBOL(xfrm_state_delete);
579
Joy Latten4aa2e622007-06-04 19:05:57 -0400580#ifdef CONFIG_SECURITY_NETWORK_XFRM
581static inline int
582xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Joy Latten4aa2e622007-06-04 19:05:57 -0400584 int i, err = 0;
585
586 for (i = 0; i <= xfrm_state_hmask; i++) {
587 struct hlist_node *entry;
588 struct xfrm_state *x;
589
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800590 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400591 if (xfrm_id_proto_match(x->id.proto, proto) &&
592 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700593 xfrm_audit_state_delete(x, 0,
594 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400595 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700596 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400597 return err;
598 }
599 }
600 }
601
602 return err;
603}
604#else
605static inline int
606xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
607{
608 return 0;
609}
610#endif
611
612int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
613{
614 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400617 err = xfrm_state_flush_secctx_check(proto, audit_info);
618 if (err)
619 goto out;
620
Masahide NAKAMURAa9917c02006-08-31 15:14:32 -0700621 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700622 struct hlist_node *entry;
623 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800625 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700627 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 xfrm_state_hold(x);
629 spin_unlock_bh(&xfrm_state_lock);
630
Joy Latten161a09e2006-11-27 13:11:54 -0600631 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700632 xfrm_audit_state_delete(x, err ? 0 : 1,
633 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400634 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700635 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 xfrm_state_put(x);
637
638 spin_lock_bh(&xfrm_state_lock);
639 goto restart;
640 }
641 }
642 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400643 err = 0;
644
645out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 spin_unlock_bh(&xfrm_state_lock);
647 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400648 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650EXPORT_SYMBOL(xfrm_state_flush);
651
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700652void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700653{
654 spin_lock_bh(&xfrm_state_lock);
655 si->sadcnt = xfrm_state_num;
656 si->sadhcnt = xfrm_state_hmask;
657 si->sadhmcnt = xfrm_state_hashmax;
658 spin_unlock_bh(&xfrm_state_lock);
659}
660EXPORT_SYMBOL(xfrm_sad_getinfo);
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662static int
663xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
664 struct xfrm_tmpl *tmpl,
665 xfrm_address_t *daddr, xfrm_address_t *saddr,
666 unsigned short family)
667{
668 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
669 if (!afinfo)
670 return -1;
671 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
672 xfrm_state_put_afinfo(afinfo);
673 return 0;
674}
675
Al Viroa94cfd12006-09-27 18:47:24 -0700676static 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 -0700677{
678 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
679 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700680 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700681
David S. Miller8f126e32006-08-24 02:45:07 -0700682 hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700683 if (x->props.family != family ||
684 x->id.spi != spi ||
685 x->id.proto != proto)
686 continue;
687
688 switch (family) {
689 case AF_INET:
690 if (x->id.daddr.a4 != daddr->a4)
691 continue;
692 break;
693 case AF_INET6:
694 if (!ipv6_addr_equal((struct in6_addr *)daddr,
695 (struct in6_addr *)
696 x->id.daddr.a6))
697 continue;
698 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700699 }
David S. Milleredcd5822006-08-24 00:42:45 -0700700
701 xfrm_state_hold(x);
702 return x;
703 }
704
705 return NULL;
706}
707
708static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
709{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700710 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700711 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700712 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700713
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800714 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700715 if (x->props.family != family ||
716 x->id.proto != proto)
717 continue;
718
719 switch (family) {
720 case AF_INET:
721 if (x->id.daddr.a4 != daddr->a4 ||
722 x->props.saddr.a4 != saddr->a4)
723 continue;
724 break;
725 case AF_INET6:
726 if (!ipv6_addr_equal((struct in6_addr *)daddr,
727 (struct in6_addr *)
728 x->id.daddr.a6) ||
729 !ipv6_addr_equal((struct in6_addr *)saddr,
730 (struct in6_addr *)
731 x->props.saddr.a6))
732 continue;
733 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700734 }
David S. Milleredcd5822006-08-24 00:42:45 -0700735
736 xfrm_state_hold(x);
737 return x;
738 }
739
740 return NULL;
741}
742
743static inline struct xfrm_state *
744__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
745{
746 if (use_spi)
747 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
748 x->id.proto, family);
749 else
750 return __xfrm_state_lookup_byaddr(&x->id.daddr,
751 &x->props.saddr,
752 x->id.proto, family);
753}
754
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700755static void xfrm_hash_grow_check(int have_hash_collision)
756{
757 if (have_hash_collision &&
758 (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
759 xfrm_state_num > xfrm_state_hmask)
760 schedule_work(&xfrm_hash_work);
761}
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900764xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 struct flowi *fl, struct xfrm_tmpl *tmpl,
766 struct xfrm_policy *pol, int *err,
767 unsigned short family)
768{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800769 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700770 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700771 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 int acquire_in_progress = 0;
773 int error = 0;
774 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900775
David S. Miller37b08e32008-09-02 20:14:15 -0700776 to_put = NULL;
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800779 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800780 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (x->props.family == family &&
782 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700783 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 xfrm_state_addr_check(x, daddr, saddr, family) &&
785 tmpl->mode == x->props.mode &&
786 tmpl->id.proto == x->id.proto &&
787 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
788 /* Resolution logic:
789 1. There is a valid state with matching selector.
790 Done.
791 2. Valid state with inappropriate selector. Skip.
792
793 Entering area of "sysdeps".
794
795 3. If state is not valid, selector is temporary,
796 it selects only session which triggered
797 previous resolution. Key manager will do
798 something to install a state with proper
799 selector.
800 */
801 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700802 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700803 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 continue;
805 if (!best ||
806 best->km.dying > x->km.dying ||
807 (best->km.dying == x->km.dying &&
808 best->curlft.add_time < x->curlft.add_time))
809 best = x;
810 } else if (x->km.state == XFRM_STATE_ACQ) {
811 acquire_in_progress = 1;
812 } else if (x->km.state == XFRM_STATE_ERROR ||
813 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700814 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700815 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 error = -ESRCH;
817 }
818 }
819 }
820
821 x = best;
822 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700823 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700824 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
825 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700826 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 error = -EEXIST;
828 goto out;
829 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800830 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (x == NULL) {
832 error = -ENOMEM;
833 goto out;
834 }
835 /* Initialize temporary selector matching only
836 * to current session. */
837 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
838
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700839 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
840 if (error) {
841 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700842 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700843 x = NULL;
844 goto out;
845 }
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (km_query(x, tmpl, pol) == 0) {
848 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800849 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800850 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700851 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800852 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 if (x->id.spi) {
854 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700855 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
David S. Miller01e67d02007-05-25 00:41:38 -0700857 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
858 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 add_timer(&x->timer);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700860 xfrm_state_num++;
861 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 } else {
863 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700864 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 x = NULL;
866 error = -ESRCH;
867 }
868 }
869out:
870 if (x)
871 xfrm_state_hold(x);
872 else
873 *err = acquire_in_progress ? -EAGAIN : error;
874 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700875 if (to_put)
876 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return x;
878}
879
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700880struct xfrm_state *
881xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
882 unsigned short family, u8 mode, u8 proto, u32 reqid)
883{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800884 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700885 struct xfrm_state *rx = NULL, *x = NULL;
886 struct hlist_node *entry;
887
888 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800889 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800890 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700891 if (x->props.family == family &&
892 x->props.reqid == reqid &&
893 !(x->props.flags & XFRM_STATE_WILDRECV) &&
894 xfrm_state_addr_check(x, daddr, saddr, family) &&
895 mode == x->props.mode &&
896 proto == x->id.proto &&
897 x->km.state == XFRM_STATE_VALID) {
898 rx = x;
899 break;
900 }
901 }
902
903 if (rx)
904 xfrm_state_hold(rx);
905 spin_unlock(&xfrm_state_lock);
906
907
908 return rx;
909}
910EXPORT_SYMBOL(xfrm_stateonly_find);
911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912static void __xfrm_state_insert(struct xfrm_state *x)
913{
David S. Millera624c102006-08-24 03:24:33 -0700914 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
David S. Miller9d4a7062006-08-24 03:18:09 -0700916 x->genid = ++xfrm_state_genid;
917
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800918 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800919
David S. Millerc1969f22006-08-24 04:00:03 -0700920 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
921 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800922 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700924 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800925 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700927 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700928 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
929 x->props.family);
930
David S. Miller8f126e32006-08-24 02:45:07 -0700931 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700932 }
933
David S. Millera47f0ce2006-08-24 03:54:22 -0700934 mod_timer(&x->timer, jiffies + HZ);
935 if (x->replay_maxage)
936 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700939
940 xfrm_state_num++;
941
David S. Miller918049f2006-10-12 22:03:24 -0700942 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943}
944
David S. Millerc7f5ea32006-08-24 03:29:04 -0700945/* xfrm_state_lock is held */
946static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
947{
948 unsigned short family = xnew->props.family;
949 u32 reqid = xnew->props.reqid;
950 struct xfrm_state *x;
951 struct hlist_node *entry;
952 unsigned int h;
953
David S. Millerc1969f22006-08-24 04:00:03 -0700954 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800955 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700956 if (x->props.family == family &&
957 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700958 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
959 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700960 x->genid = xfrm_state_genid;
961 }
962}
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964void xfrm_state_insert(struct xfrm_state *x)
965{
966 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700967 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 __xfrm_state_insert(x);
969 spin_unlock_bh(&xfrm_state_lock);
970}
971EXPORT_SYMBOL(xfrm_state_insert);
972
David S. Miller27708342006-08-24 00:13:10 -0700973/* xfrm_state_lock is held */
974static 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)
975{
David S. Millerc1969f22006-08-24 04:00:03 -0700976 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700977 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700978 struct xfrm_state *x;
979
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800980 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700981 if (x->props.reqid != reqid ||
982 x->props.mode != mode ||
983 x->props.family != family ||
984 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700985 x->id.spi != 0 ||
986 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700987 continue;
988
989 switch (family) {
990 case AF_INET:
991 if (x->id.daddr.a4 != daddr->a4 ||
992 x->props.saddr.a4 != saddr->a4)
993 continue;
994 break;
995 case AF_INET6:
996 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
997 (struct in6_addr *)daddr) ||
998 !ipv6_addr_equal((struct in6_addr *)
999 x->props.saddr.a6,
1000 (struct in6_addr *)saddr))
1001 continue;
1002 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001003 }
David S. Miller27708342006-08-24 00:13:10 -07001004
1005 xfrm_state_hold(x);
1006 return x;
1007 }
1008
1009 if (!create)
1010 return NULL;
1011
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001012 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001013 if (likely(x)) {
1014 switch (family) {
1015 case AF_INET:
1016 x->sel.daddr.a4 = daddr->a4;
1017 x->sel.saddr.a4 = saddr->a4;
1018 x->sel.prefixlen_d = 32;
1019 x->sel.prefixlen_s = 32;
1020 x->props.saddr.a4 = saddr->a4;
1021 x->id.daddr.a4 = daddr->a4;
1022 break;
1023
1024 case AF_INET6:
1025 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1026 (struct in6_addr *)daddr);
1027 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1028 (struct in6_addr *)saddr);
1029 x->sel.prefixlen_d = 128;
1030 x->sel.prefixlen_s = 128;
1031 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1032 (struct in6_addr *)saddr);
1033 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1034 (struct in6_addr *)daddr);
1035 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001036 }
David S. Miller27708342006-08-24 00:13:10 -07001037
1038 x->km.state = XFRM_STATE_ACQ;
1039 x->id.proto = proto;
1040 x->props.family = family;
1041 x->props.mode = mode;
1042 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001043 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001044 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001045 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001046 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001047 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001048 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001049 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001050 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001051
1052 xfrm_state_num++;
1053
1054 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001055 }
1056
1057 return x;
1058}
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1061
1062int xfrm_state_add(struct xfrm_state *x)
1063{
David S. Miller37b08e32008-09-02 20:14:15 -07001064 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 int family;
1066 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001067 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
David S. Miller37b08e32008-09-02 20:14:15 -07001071 to_put = NULL;
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 spin_lock_bh(&xfrm_state_lock);
1074
David S. Milleredcd5822006-08-24 00:42:45 -07001075 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001077 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 x1 = NULL;
1079 err = -EEXIST;
1080 goto out;
1081 }
1082
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001083 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001085 if (x1 && ((x1->id.proto != x->id.proto) ||
1086 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001087 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 x1 = NULL;
1089 }
1090 }
1091
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001092 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001093 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1094 x->id.proto,
1095 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
David S. Millerc7f5ea32006-08-24 03:29:04 -07001097 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 __xfrm_state_insert(x);
1099 err = 0;
1100
1101out:
1102 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 if (x1) {
1105 xfrm_state_delete(x1);
1106 xfrm_state_put(x1);
1107 }
1108
David S. Miller37b08e32008-09-02 20:14:15 -07001109 if (to_put)
1110 xfrm_state_put(to_put);
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return err;
1113}
1114EXPORT_SYMBOL(xfrm_state_add);
1115
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001116#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001117static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001118{
1119 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001120 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001121 if (!x)
1122 goto error;
1123
1124 memcpy(&x->id, &orig->id, sizeof(x->id));
1125 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1126 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1127 x->props.mode = orig->props.mode;
1128 x->props.replay_window = orig->props.replay_window;
1129 x->props.reqid = orig->props.reqid;
1130 x->props.family = orig->props.family;
1131 x->props.saddr = orig->props.saddr;
1132
1133 if (orig->aalg) {
1134 x->aalg = xfrm_algo_clone(orig->aalg);
1135 if (!x->aalg)
1136 goto error;
1137 }
1138 x->props.aalgo = orig->props.aalgo;
1139
1140 if (orig->ealg) {
1141 x->ealg = xfrm_algo_clone(orig->ealg);
1142 if (!x->ealg)
1143 goto error;
1144 }
1145 x->props.ealgo = orig->props.ealgo;
1146
1147 if (orig->calg) {
1148 x->calg = xfrm_algo_clone(orig->calg);
1149 if (!x->calg)
1150 goto error;
1151 }
1152 x->props.calgo = orig->props.calgo;
1153
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001154 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001155 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1156 if (!x->encap)
1157 goto error;
1158 }
1159
1160 if (orig->coaddr) {
1161 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1162 GFP_KERNEL);
1163 if (!x->coaddr)
1164 goto error;
1165 }
1166
1167 err = xfrm_init_state(x);
1168 if (err)
1169 goto error;
1170
1171 x->props.flags = orig->props.flags;
1172
1173 x->curlft.add_time = orig->curlft.add_time;
1174 x->km.state = orig->km.state;
1175 x->km.seq = orig->km.seq;
1176
1177 return x;
1178
1179 error:
1180 if (errp)
1181 *errp = err;
1182 if (x) {
1183 kfree(x->aalg);
1184 kfree(x->ealg);
1185 kfree(x->calg);
1186 kfree(x->encap);
1187 kfree(x->coaddr);
1188 }
1189 kfree(x);
1190 return NULL;
1191}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001192
1193/* xfrm_state_lock is held */
1194struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1195{
1196 unsigned int h;
1197 struct xfrm_state *x;
1198 struct hlist_node *entry;
1199
1200 if (m->reqid) {
1201 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1202 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001203 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001204 if (x->props.mode != m->mode ||
1205 x->id.proto != m->proto)
1206 continue;
1207 if (m->reqid && x->props.reqid != m->reqid)
1208 continue;
1209 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1210 m->old_family) ||
1211 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1212 m->old_family))
1213 continue;
1214 xfrm_state_hold(x);
1215 return x;
1216 }
1217 } else {
1218 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1219 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001220 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001221 if (x->props.mode != m->mode ||
1222 x->id.proto != m->proto)
1223 continue;
1224 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1225 m->old_family) ||
1226 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1227 m->old_family))
1228 continue;
1229 xfrm_state_hold(x);
1230 return x;
1231 }
1232 }
1233
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001234 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001235}
1236EXPORT_SYMBOL(xfrm_migrate_state_find);
1237
1238struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1239 struct xfrm_migrate *m)
1240{
1241 struct xfrm_state *xc;
1242 int err;
1243
1244 xc = xfrm_state_clone(x, &err);
1245 if (!xc)
1246 return NULL;
1247
1248 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1249 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1250
1251 /* add state */
1252 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1253 /* a care is needed when the destination address of the
1254 state is to be updated as it is a part of triplet */
1255 xfrm_state_insert(xc);
1256 } else {
1257 if ((err = xfrm_state_add(xc)) < 0)
1258 goto error;
1259 }
1260
1261 return xc;
1262error:
1263 kfree(xc);
1264 return NULL;
1265}
1266EXPORT_SYMBOL(xfrm_state_migrate);
1267#endif
1268
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269int xfrm_state_update(struct xfrm_state *x)
1270{
David S. Miller37b08e32008-09-02 20:14:15 -07001271 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001273 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
David S. Miller37b08e32008-09-02 20:14:15 -07001275 to_put = NULL;
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001278 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280 err = -ESRCH;
1281 if (!x1)
1282 goto out;
1283
1284 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001285 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 err = -EEXIST;
1287 goto out;
1288 }
1289
1290 if (x1->km.state == XFRM_STATE_ACQ) {
1291 __xfrm_state_insert(x);
1292 x = NULL;
1293 }
1294 err = 0;
1295
1296out:
1297 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
David S. Miller37b08e32008-09-02 20:14:15 -07001299 if (to_put)
1300 xfrm_state_put(to_put);
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (err)
1303 return err;
1304
1305 if (!x) {
1306 xfrm_state_delete(x1);
1307 xfrm_state_put(x1);
1308 return 0;
1309 }
1310
1311 err = -EINVAL;
1312 spin_lock_bh(&x1->lock);
1313 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1314 if (x->encap && x1->encap)
1315 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001316 if (x->coaddr && x1->coaddr) {
1317 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1318 }
1319 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1320 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1322 x1->km.dying = 0;
1323
David S. Millera47f0ce2006-08-24 03:54:22 -07001324 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 if (x1->curlft.use_time)
1326 xfrm_state_check_expire(x1);
1327
1328 err = 0;
1329 }
1330 spin_unlock_bh(&x1->lock);
1331
1332 xfrm_state_put(x1);
1333
1334 return err;
1335}
1336EXPORT_SYMBOL(xfrm_state_update);
1337
1338int xfrm_state_check_expire(struct xfrm_state *x)
1339{
1340 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001341 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343 if (x->km.state != XFRM_STATE_VALID)
1344 return -EINVAL;
1345
1346 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1347 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001348 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001349 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 return -EINVAL;
1351 }
1352
1353 if (!x->km.dying &&
1354 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001355 x->curlft.packets >= x->lft.soft_packet_limit)) {
1356 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001357 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 return 0;
1360}
1361EXPORT_SYMBOL(xfrm_state_check_expire);
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001364xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 unsigned short family)
1366{
1367 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001370 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 return x;
1373}
1374EXPORT_SYMBOL(xfrm_state_lookup);
1375
1376struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001377xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1378 u8 proto, unsigned short family)
1379{
1380 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001381
1382 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001383 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001384 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001385 return x;
1386}
1387EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1388
1389struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001390xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1391 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 int create, unsigned short family)
1393{
1394 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001397 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 return x;
1401}
1402EXPORT_SYMBOL(xfrm_find_acq);
1403
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001404#ifdef CONFIG_XFRM_SUB_POLICY
1405int
1406xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1407 unsigned short family)
1408{
1409 int err = 0;
1410 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1411 if (!afinfo)
1412 return -EAFNOSUPPORT;
1413
1414 spin_lock_bh(&xfrm_state_lock);
1415 if (afinfo->tmpl_sort)
1416 err = afinfo->tmpl_sort(dst, src, n);
1417 spin_unlock_bh(&xfrm_state_lock);
1418 xfrm_state_put_afinfo(afinfo);
1419 return err;
1420}
1421EXPORT_SYMBOL(xfrm_tmpl_sort);
1422
1423int
1424xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1425 unsigned short family)
1426{
1427 int err = 0;
1428 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1429 if (!afinfo)
1430 return -EAFNOSUPPORT;
1431
1432 spin_lock_bh(&xfrm_state_lock);
1433 if (afinfo->state_sort)
1434 err = afinfo->state_sort(dst, src, n);
1435 spin_unlock_bh(&xfrm_state_lock);
1436 xfrm_state_put_afinfo(afinfo);
1437 return err;
1438}
1439EXPORT_SYMBOL(xfrm_state_sort);
1440#endif
1441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442/* Silly enough, but I'm lazy to build resolution list */
1443
1444static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1445{
1446 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
David S. Millerf034b5d2006-08-24 03:08:07 -07001448 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001449 struct hlist_node *entry;
1450 struct xfrm_state *x;
1451
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001452 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001453 if (x->km.seq == seq &&
1454 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 xfrm_state_hold(x);
1456 return x;
1457 }
1458 }
1459 }
1460 return NULL;
1461}
1462
1463struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1464{
1465 struct xfrm_state *x;
1466
1467 spin_lock_bh(&xfrm_state_lock);
1468 x = __xfrm_find_acq_byseq(seq);
1469 spin_unlock_bh(&xfrm_state_lock);
1470 return x;
1471}
1472EXPORT_SYMBOL(xfrm_find_acq_byseq);
1473
1474u32 xfrm_get_acqseq(void)
1475{
1476 u32 res;
1477 static u32 acqseq;
1478 static DEFINE_SPINLOCK(acqseq_lock);
1479
1480 spin_lock_bh(&acqseq_lock);
1481 res = (++acqseq ? : ++acqseq);
1482 spin_unlock_bh(&acqseq_lock);
1483 return res;
1484}
1485EXPORT_SYMBOL(xfrm_get_acqseq);
1486
Herbert Xu658b2192007-10-09 13:29:52 -07001487int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488{
David S. Millerf034b5d2006-08-24 03:08:07 -07001489 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001491 int err = -ENOENT;
1492 __be32 minspi = htonl(low);
1493 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Herbert Xu658b2192007-10-09 13:29:52 -07001495 spin_lock_bh(&x->lock);
1496 if (x->km.state == XFRM_STATE_DEAD)
1497 goto unlock;
1498
1499 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001501 goto unlock;
1502
1503 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 if (minspi == maxspi) {
1506 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1507 if (x0) {
1508 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001509 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 }
1511 x->id.spi = minspi;
1512 } else {
1513 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001514 for (h=0; h<high-low+1; h++) {
1515 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1517 if (x0 == NULL) {
1518 x->id.spi = htonl(spi);
1519 break;
1520 }
1521 xfrm_state_put(x0);
1522 }
1523 }
1524 if (x->id.spi) {
1525 spin_lock_bh(&xfrm_state_lock);
1526 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -07001527 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001529
1530 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 }
Herbert Xu658b2192007-10-09 13:29:52 -07001532
1533unlock:
1534 spin_unlock_bh(&x->lock);
1535
1536 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537}
1538EXPORT_SYMBOL(xfrm_alloc_spi);
1539
Timo Teras4c563f72008-02-28 21:31:08 -08001540int xfrm_state_walk(struct xfrm_state_walk *walk,
1541 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 void *data)
1543{
Herbert Xu12a169e2008-10-01 07:03:24 -07001544 struct xfrm_state *state;
1545 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 int err = 0;
1547
Herbert Xu12a169e2008-10-01 07:03:24 -07001548 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001549 return 0;
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001552 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001553 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001554 else
1555 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001556 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001557 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001558 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001559 state = container_of(x, struct xfrm_state, km);
1560 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001561 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001562 err = func(state, walk->seq, data);
1563 if (err) {
1564 list_move_tail(&walk->all, &x->all);
1565 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001567 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001569 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 err = -ENOENT;
1571 goto out;
1572 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001573 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574out:
1575 spin_unlock_bh(&xfrm_state_lock);
1576 return err;
1577}
1578EXPORT_SYMBOL(xfrm_state_walk);
1579
Herbert Xu5c182452008-09-22 19:48:19 -07001580void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1581{
Herbert Xu12a169e2008-10-01 07:03:24 -07001582 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001583 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001584 walk->state = XFRM_STATE_DEAD;
1585 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001586}
1587EXPORT_SYMBOL(xfrm_state_walk_init);
1588
Herbert Xuabb81c42008-09-09 19:58:29 -07001589void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1590{
Herbert Xu12a169e2008-10-01 07:03:24 -07001591 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001592 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001593
Herbert Xu12a169e2008-10-01 07:03:24 -07001594 spin_lock_bh(&xfrm_state_lock);
1595 list_del(&walk->all);
1596 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001597}
1598EXPORT_SYMBOL(xfrm_state_walk_done);
1599
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001600
1601void xfrm_replay_notify(struct xfrm_state *x, int event)
1602{
1603 struct km_event c;
1604 /* we send notify messages in case
1605 * 1. we updated on of the sequence numbers, and the seqno difference
1606 * is at least x->replay_maxdiff, in this case we also update the
1607 * timeout of our timer function
1608 * 2. if x->replay_maxage has elapsed since last update,
1609 * and there were changes
1610 *
1611 * The state structure must be locked!
1612 */
1613
1614 switch (event) {
1615 case XFRM_REPLAY_UPDATE:
1616 if (x->replay_maxdiff &&
1617 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001618 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1619 if (x->xflags & XFRM_TIME_DEFER)
1620 event = XFRM_REPLAY_TIMEOUT;
1621 else
1622 return;
1623 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001624
1625 break;
1626
1627 case XFRM_REPLAY_TIMEOUT:
1628 if ((x->replay.seq == x->preplay.seq) &&
1629 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001630 (x->replay.oseq == x->preplay.oseq)) {
1631 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001632 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001633 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001634
1635 break;
1636 }
1637
1638 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1639 c.event = XFRM_MSG_NEWAE;
1640 c.data.aevent = event;
1641 km_state_notify(x, &c);
1642
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001643 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001644 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001645 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001646}
1647
1648static void xfrm_replay_timer_handler(unsigned long data)
1649{
1650 struct xfrm_state *x = (struct xfrm_state*)data;
1651
1652 spin_lock(&x->lock);
1653
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001654 if (x->km.state == XFRM_STATE_VALID) {
1655 if (xfrm_aevent_is_on())
1656 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1657 else
1658 x->xflags |= XFRM_TIME_DEFER;
1659 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001660
1661 spin_unlock(&x->lock);
1662}
1663
Paul Mooreafeb14b2007-12-21 14:58:11 -08001664int xfrm_replay_check(struct xfrm_state *x,
1665 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
1667 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001668 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001671 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673 if (likely(seq > x->replay.seq))
1674 return 0;
1675
1676 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001677 if (diff >= min_t(unsigned int, x->props.replay_window,
1678 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001680 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
1682
1683 if (x->replay.bitmap & (1U << diff)) {
1684 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001685 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
1687 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001688
1689err:
1690 xfrm_audit_state_replay(x, skb, net_seq);
1691 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Al Viro61f46272006-09-27 18:48:33 -07001694void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695{
1696 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001697 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 if (seq > x->replay.seq) {
1700 diff = seq - x->replay.seq;
1701 if (diff < x->props.replay_window)
1702 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1703 else
1704 x->replay.bitmap = 1;
1705 x->replay.seq = seq;
1706 } else {
1707 diff = x->replay.seq - seq;
1708 x->replay.bitmap |= (1U << diff);
1709 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001710
1711 if (xfrm_aevent_is_on())
1712 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Denis Chengdf018122007-12-07 00:51:11 -08001715static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716static DEFINE_RWLOCK(xfrm_km_lock);
1717
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001718void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719{
1720 struct xfrm_mgr *km;
1721
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001722 read_lock(&xfrm_km_lock);
1723 list_for_each_entry(km, &xfrm_km_list, list)
1724 if (km->notify_policy)
1725 km->notify_policy(xp, dir, c);
1726 read_unlock(&xfrm_km_lock);
1727}
1728
1729void km_state_notify(struct xfrm_state *x, struct km_event *c)
1730{
1731 struct xfrm_mgr *km;
1732 read_lock(&xfrm_km_lock);
1733 list_for_each_entry(km, &xfrm_km_list, list)
1734 if (km->notify)
1735 km->notify(x, c);
1736 read_unlock(&xfrm_km_lock);
1737}
1738
1739EXPORT_SYMBOL(km_policy_notify);
1740EXPORT_SYMBOL(km_state_notify);
1741
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001742void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001743{
1744 struct km_event c;
1745
Herbert Xubf088672005-06-18 22:44:00 -07001746 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001747 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001748 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001749 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
1751 if (hard)
1752 wake_up(&km_waitq);
1753}
1754
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001755EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001756/*
1757 * We send to all registered managers regardless of failure
1758 * We are happy with one success
1759*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001760int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001762 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 struct xfrm_mgr *km;
1764
1765 read_lock(&xfrm_km_lock);
1766 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001767 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1768 if (!acqret)
1769 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 }
1771 read_unlock(&xfrm_km_lock);
1772 return err;
1773}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001774EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
Al Viro5d36b182006-11-08 00:24:06 -08001776int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 int err = -EINVAL;
1779 struct xfrm_mgr *km;
1780
1781 read_lock(&xfrm_km_lock);
1782 list_for_each_entry(km, &xfrm_km_list, list) {
1783 if (km->new_mapping)
1784 err = km->new_mapping(x, ipaddr, sport);
1785 if (!err)
1786 break;
1787 }
1788 read_unlock(&xfrm_km_lock);
1789 return err;
1790}
1791EXPORT_SYMBOL(km_new_mapping);
1792
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001793void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001795 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Herbert Xubf088672005-06-18 22:44:00 -07001797 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001798 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001799 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001800 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802 if (hard)
1803 wake_up(&km_waitq);
1804}
David S. Millera70fcb02006-03-20 19:18:52 -08001805EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001807#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001808int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001809 struct xfrm_migrate *m, int num_migrate,
1810 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001811{
1812 int err = -EINVAL;
1813 int ret;
1814 struct xfrm_mgr *km;
1815
1816 read_lock(&xfrm_km_lock);
1817 list_for_each_entry(km, &xfrm_km_list, list) {
1818 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001819 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001820 if (!ret)
1821 err = ret;
1822 }
1823 }
1824 read_unlock(&xfrm_km_lock);
1825 return err;
1826}
1827EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001828#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001829
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001830int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1831{
1832 int err = -EINVAL;
1833 int ret;
1834 struct xfrm_mgr *km;
1835
1836 read_lock(&xfrm_km_lock);
1837 list_for_each_entry(km, &xfrm_km_list, list) {
1838 if (km->report) {
1839 ret = km->report(proto, sel, addr);
1840 if (!ret)
1841 err = ret;
1842 }
1843 }
1844 read_unlock(&xfrm_km_lock);
1845 return err;
1846}
1847EXPORT_SYMBOL(km_report);
1848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1850{
1851 int err;
1852 u8 *data;
1853 struct xfrm_mgr *km;
1854 struct xfrm_policy *pol = NULL;
1855
1856 if (optlen <= 0 || optlen > PAGE_SIZE)
1857 return -EMSGSIZE;
1858
1859 data = kmalloc(optlen, GFP_KERNEL);
1860 if (!data)
1861 return -ENOMEM;
1862
1863 err = -EFAULT;
1864 if (copy_from_user(data, optval, optlen))
1865 goto out;
1866
1867 err = -EINVAL;
1868 read_lock(&xfrm_km_lock);
1869 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001870 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 optlen, &err);
1872 if (err >= 0)
1873 break;
1874 }
1875 read_unlock(&xfrm_km_lock);
1876
1877 if (err >= 0) {
1878 xfrm_sk_policy_insert(sk, err, pol);
1879 xfrm_pol_put(pol);
1880 err = 0;
1881 }
1882
1883out:
1884 kfree(data);
1885 return err;
1886}
1887EXPORT_SYMBOL(xfrm_user_policy);
1888
1889int xfrm_register_km(struct xfrm_mgr *km)
1890{
1891 write_lock_bh(&xfrm_km_lock);
1892 list_add_tail(&km->list, &xfrm_km_list);
1893 write_unlock_bh(&xfrm_km_lock);
1894 return 0;
1895}
1896EXPORT_SYMBOL(xfrm_register_km);
1897
1898int xfrm_unregister_km(struct xfrm_mgr *km)
1899{
1900 write_lock_bh(&xfrm_km_lock);
1901 list_del(&km->list);
1902 write_unlock_bh(&xfrm_km_lock);
1903 return 0;
1904}
1905EXPORT_SYMBOL(xfrm_unregister_km);
1906
1907int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1908{
1909 int err = 0;
1910 if (unlikely(afinfo == NULL))
1911 return -EINVAL;
1912 if (unlikely(afinfo->family >= NPROTO))
1913 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001914 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1916 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001917 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001919 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 return err;
1921}
1922EXPORT_SYMBOL(xfrm_state_register_afinfo);
1923
1924int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1925{
1926 int err = 0;
1927 if (unlikely(afinfo == NULL))
1928 return -EINVAL;
1929 if (unlikely(afinfo->family >= NPROTO))
1930 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001931 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1933 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1934 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001935 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001938 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 return err;
1940}
1941EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1942
Herbert Xu17c2a422007-10-17 21:33:12 -07001943static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944{
1945 struct xfrm_state_afinfo *afinfo;
1946 if (unlikely(family >= NPROTO))
1947 return NULL;
1948 read_lock(&xfrm_state_afinfo_lock);
1949 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001950 if (unlikely(!afinfo))
1951 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 return afinfo;
1953}
1954
Herbert Xu17c2a422007-10-17 21:33:12 -07001955static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001956 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957{
Herbert Xu546be242006-05-27 23:03:58 -07001958 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959}
1960
1961/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1962void xfrm_state_delete_tunnel(struct xfrm_state *x)
1963{
1964 if (x->tunnel) {
1965 struct xfrm_state *t = x->tunnel;
1966
1967 if (atomic_read(&t->tunnel_users) == 2)
1968 xfrm_state_delete(t);
1969 atomic_dec(&t->tunnel_users);
1970 xfrm_state_put(t);
1971 x->tunnel = NULL;
1972 }
1973}
1974EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1975
1976int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1977{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001978 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979
Patrick McHardyc5c25232007-04-09 11:47:18 -07001980 spin_lock_bh(&x->lock);
1981 if (x->km.state == XFRM_STATE_VALID &&
1982 x->type && x->type->get_mtu)
1983 res = x->type->get_mtu(x, mtu);
1984 else
Patrick McHardy28121612007-06-18 22:30:15 -07001985 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001986 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 return res;
1988}
1989
Herbert Xu72cb6962005-06-20 13:18:08 -07001990int xfrm_init_state(struct xfrm_state *x)
1991{
Herbert Xud094cd82005-06-20 13:19:41 -07001992 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001993 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001994 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001995 int err;
1996
Herbert Xud094cd82005-06-20 13:19:41 -07001997 err = -EAFNOSUPPORT;
1998 afinfo = xfrm_state_get_afinfo(family);
1999 if (!afinfo)
2000 goto error;
2001
2002 err = 0;
2003 if (afinfo->init_flags)
2004 err = afinfo->init_flags(x);
2005
2006 xfrm_state_put_afinfo(afinfo);
2007
2008 if (err)
2009 goto error;
2010
2011 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002012
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002013 if (x->sel.family != AF_UNSPEC) {
2014 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2015 if (inner_mode == NULL)
2016 goto error;
2017
2018 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2019 family != x->sel.family) {
2020 xfrm_put_mode(inner_mode);
2021 goto error;
2022 }
2023
2024 x->inner_mode = inner_mode;
2025 } else {
2026 struct xfrm_mode *inner_mode_iaf;
2027
2028 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2029 if (inner_mode == NULL)
2030 goto error;
2031
2032 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2033 xfrm_put_mode(inner_mode);
2034 goto error;
2035 }
2036
2037 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2038 if (inner_mode_iaf == NULL)
2039 goto error;
2040
2041 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2042 xfrm_put_mode(inner_mode_iaf);
2043 goto error;
2044 }
2045
2046 if (x->props.family == AF_INET) {
2047 x->inner_mode = inner_mode;
2048 x->inner_mode_iaf = inner_mode_iaf;
2049 } else {
2050 x->inner_mode = inner_mode_iaf;
2051 x->inner_mode_iaf = inner_mode;
2052 }
2053 }
Herbert Xu13996372007-10-17 21:35:51 -07002054
Herbert Xud094cd82005-06-20 13:19:41 -07002055 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002056 if (x->type == NULL)
2057 goto error;
2058
2059 err = x->type->init_state(x);
2060 if (err)
2061 goto error;
2062
Herbert Xu13996372007-10-17 21:35:51 -07002063 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2064 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002065 goto error;
2066
Herbert Xu72cb6962005-06-20 13:18:08 -07002067 x->km.state = XFRM_STATE_VALID;
2068
2069error:
2070 return err;
2071}
2072
2073EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002074
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002075int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076{
David S. Millerf034b5d2006-08-24 03:08:07 -07002077 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002079 INIT_LIST_HEAD(&net->xfrm.state_all);
2080
David S. Millerf034b5d2006-08-24 03:08:07 -07002081 sz = sizeof(struct hlist_head) * 8;
2082
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002083 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2084 if (!net->xfrm.state_bydst)
2085 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002086 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2087 if (!net->xfrm.state_bysrc)
2088 goto out_bysrc;
David S. Miller44e36b42006-08-24 04:50:50 -07002089 xfrm_state_byspi = xfrm_hash_alloc(sz);
David S. Millerf034b5d2006-08-24 03:08:07 -07002090 xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
2091
David Howellsc4028952006-11-22 14:57:56 +00002092 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002093 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002094
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002095out_bysrc:
2096 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002097out_bydst:
2098 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002099}
2100
2101void xfrm_state_fini(struct net *net)
2102{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002103 unsigned int sz;
2104
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002105 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002106
2107 sz = (xfrm_state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002108 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2109 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002110 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2111 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112}
2113
Joy Lattenab5f5e82007-09-17 11:51:22 -07002114#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002115static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2116 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002117{
Paul Moore68277ac2007-12-20 20:49:33 -08002118 struct xfrm_sec_ctx *ctx = x->security;
2119 u32 spi = ntohl(x->id.spi);
2120
2121 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002122 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002123 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002124
2125 switch(x->props.family) {
2126 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002127 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2128 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002129 break;
2130 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002131 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002132 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002133 break;
2134 }
Paul Moore68277ac2007-12-20 20:49:33 -08002135
2136 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002137}
2138
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002139static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2140 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002141{
2142 struct iphdr *iph4;
2143 struct ipv6hdr *iph6;
2144
2145 switch (family) {
2146 case AF_INET:
2147 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002148 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2149 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002150 break;
2151 case AF_INET6:
2152 iph6 = ipv6_hdr(skb);
2153 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002154 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002155 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002156 iph6->flow_lbl[0] & 0x0f,
2157 iph6->flow_lbl[1],
2158 iph6->flow_lbl[2]);
2159 break;
2160 }
2161}
2162
Paul Moore68277ac2007-12-20 20:49:33 -08002163void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002164 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002165{
2166 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002167
Paul Mooreafeb14b2007-12-21 14:58:11 -08002168 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002169 if (audit_buf == NULL)
2170 return;
Eric Paris25323862008-04-18 10:09:25 -04002171 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002172 xfrm_audit_helper_sainfo(x, audit_buf);
2173 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002174 audit_log_end(audit_buf);
2175}
2176EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2177
Paul Moore68277ac2007-12-20 20:49:33 -08002178void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002179 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002180{
2181 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002182
Paul Mooreafeb14b2007-12-21 14:58:11 -08002183 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002184 if (audit_buf == NULL)
2185 return;
Eric Paris25323862008-04-18 10:09:25 -04002186 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002187 xfrm_audit_helper_sainfo(x, audit_buf);
2188 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002189 audit_log_end(audit_buf);
2190}
2191EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002192
2193void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2194 struct sk_buff *skb)
2195{
2196 struct audit_buffer *audit_buf;
2197 u32 spi;
2198
2199 audit_buf = xfrm_audit_start("SA-replay-overflow");
2200 if (audit_buf == NULL)
2201 return;
2202 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2203 /* don't record the sequence number because it's inherent in this kind
2204 * of audit message */
2205 spi = ntohl(x->id.spi);
2206 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2207 audit_log_end(audit_buf);
2208}
2209EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2210
2211static void xfrm_audit_state_replay(struct xfrm_state *x,
2212 struct sk_buff *skb, __be32 net_seq)
2213{
2214 struct audit_buffer *audit_buf;
2215 u32 spi;
2216
2217 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2218 if (audit_buf == NULL)
2219 return;
2220 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2221 spi = ntohl(x->id.spi);
2222 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2223 spi, spi, ntohl(net_seq));
2224 audit_log_end(audit_buf);
2225}
2226
2227void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2228{
2229 struct audit_buffer *audit_buf;
2230
2231 audit_buf = xfrm_audit_start("SA-notfound");
2232 if (audit_buf == NULL)
2233 return;
2234 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2235 audit_log_end(audit_buf);
2236}
2237EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2238
2239void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2240 __be32 net_spi, __be32 net_seq)
2241{
2242 struct audit_buffer *audit_buf;
2243 u32 spi;
2244
2245 audit_buf = xfrm_audit_start("SA-notfound");
2246 if (audit_buf == NULL)
2247 return;
2248 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2249 spi = ntohl(net_spi);
2250 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2251 spi, spi, ntohl(net_seq));
2252 audit_log_end(audit_buf);
2253}
2254EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2255
2256void xfrm_audit_state_icvfail(struct xfrm_state *x,
2257 struct sk_buff *skb, u8 proto)
2258{
2259 struct audit_buffer *audit_buf;
2260 __be32 net_spi;
2261 __be32 net_seq;
2262
2263 audit_buf = xfrm_audit_start("SA-icv-failure");
2264 if (audit_buf == NULL)
2265 return;
2266 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2267 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2268 u32 spi = ntohl(net_spi);
2269 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2270 spi, spi, ntohl(net_seq));
2271 }
2272 audit_log_end(audit_buf);
2273}
2274EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002275#endif /* CONFIG_AUDITSYSCALL */