blob: 66ca1ef7f8eb55481b5b5224e0104ca4f96c84ce [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 unsigned int xfrm_state_hmask __read_mostly;
48static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
49static unsigned int xfrm_state_num;
David S. Miller9d4a7062006-08-24 03:18:09 -070050static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Herbert Xu17c2a422007-10-17 21:33:12 -070052static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
53static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
54
Paul Mooreafeb14b2007-12-21 14:58:11 -080055#ifdef CONFIG_AUDITSYSCALL
56static void xfrm_audit_state_replay(struct xfrm_state *x,
57 struct sk_buff *skb, __be32 net_seq);
58#else
59#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
60#endif /* CONFIG_AUDITSYSCALL */
61
David S. Millerc1969f22006-08-24 04:00:03 -070062static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
63 xfrm_address_t *saddr,
64 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070065 unsigned short family)
66{
David S. Millerc1969f22006-08-24 04:00:03 -070067 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070068}
69
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070070static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
71 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070072 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070073{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070074 return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070075}
76
David S. Miller2575b652006-08-24 03:26:44 -070077static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070078xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070079{
David S. Millerc1969f22006-08-24 04:00:03 -070080 return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070081}
82
David S. Millerf034b5d2006-08-24 03:08:07 -070083static void xfrm_hash_transfer(struct hlist_head *list,
84 struct hlist_head *ndsttable,
85 struct hlist_head *nsrctable,
86 struct hlist_head *nspitable,
87 unsigned int nhashmask)
88{
89 struct hlist_node *entry, *tmp;
90 struct xfrm_state *x;
91
92 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
93 unsigned int h;
94
David S. Millerc1969f22006-08-24 04:00:03 -070095 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
96 x->props.reqid, x->props.family,
97 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070098 hlist_add_head(&x->bydst, ndsttable+h);
99
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700100 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
101 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700102 nhashmask);
103 hlist_add_head(&x->bysrc, nsrctable+h);
104
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700105 if (x->id.spi) {
106 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
107 x->id.proto, x->props.family,
108 nhashmask);
109 hlist_add_head(&x->byspi, nspitable+h);
110 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700111 }
112}
113
114static unsigned long xfrm_hash_new_size(void)
115{
116 return ((xfrm_state_hmask + 1) << 1) *
117 sizeof(struct hlist_head);
118}
119
120static DEFINE_MUTEX(hash_resize_mutex);
121
David Howellsc4028952006-11-22 14:57:56 +0000122static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700123{
124 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
125 unsigned long nsize, osize;
126 unsigned int nhashmask, ohashmask;
127 int i;
128
129 mutex_lock(&hash_resize_mutex);
130
131 nsize = xfrm_hash_new_size();
David S. Miller44e36b42006-08-24 04:50:50 -0700132 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700133 if (!ndst)
134 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700135 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700136 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700137 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700138 goto out_unlock;
139 }
David S. Miller44e36b42006-08-24 04:50:50 -0700140 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700141 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700142 xfrm_hash_free(ndst, nsize);
143 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700144 goto out_unlock;
145 }
146
147 spin_lock_bh(&xfrm_state_lock);
148
149 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
150 for (i = xfrm_state_hmask; i >= 0; i--)
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800151 xfrm_hash_transfer(init_net.xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700152 nhashmask);
153
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800154 odst = init_net.xfrm.state_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800155 osrc = init_net.xfrm.state_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800156 ospi = init_net.xfrm.state_byspi;
David S. Millerf034b5d2006-08-24 03:08:07 -0700157 ohashmask = xfrm_state_hmask;
158
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800159 init_net.xfrm.state_bydst = ndst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800160 init_net.xfrm.state_bysrc = nsrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800161 init_net.xfrm.state_byspi = nspi;
David S. Millerf034b5d2006-08-24 03:08:07 -0700162 xfrm_state_hmask = nhashmask;
163
164 spin_unlock_bh(&xfrm_state_lock);
165
166 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700167 xfrm_hash_free(odst, osize);
168 xfrm_hash_free(osrc, osize);
169 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700170
171out_unlock:
172 mutex_unlock(&hash_resize_mutex);
173}
174
David Howellsc4028952006-11-22 14:57:56 +0000175static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177DECLARE_WAIT_QUEUE_HEAD(km_waitq);
178EXPORT_SYMBOL(km_waitq);
179
180static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
181static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
182
183static struct work_struct xfrm_state_gc_work;
Herbert Xu12a169e2008-10-01 07:03:24 -0700184static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static DEFINE_SPINLOCK(xfrm_state_gc_lock);
186
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800187int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800189int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800190void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700192static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
193{
194 struct xfrm_state_afinfo *afinfo;
195 if (unlikely(family >= NPROTO))
196 return NULL;
197 write_lock_bh(&xfrm_state_afinfo_lock);
198 afinfo = xfrm_state_afinfo[family];
199 if (unlikely(!afinfo))
200 write_unlock_bh(&xfrm_state_afinfo_lock);
201 return afinfo;
202}
203
204static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800205 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700206{
207 write_unlock_bh(&xfrm_state_afinfo_lock);
208}
209
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800210int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700211{
212 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800213 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700214 int err = 0;
215
216 if (unlikely(afinfo == NULL))
217 return -EAFNOSUPPORT;
218 typemap = afinfo->type_map;
219
220 if (likely(typemap[type->proto] == NULL))
221 typemap[type->proto] = type;
222 else
223 err = -EEXIST;
224 xfrm_state_unlock_afinfo(afinfo);
225 return err;
226}
227EXPORT_SYMBOL(xfrm_register_type);
228
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800229int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700230{
231 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800232 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700233 int err = 0;
234
235 if (unlikely(afinfo == NULL))
236 return -EAFNOSUPPORT;
237 typemap = afinfo->type_map;
238
239 if (unlikely(typemap[type->proto] != type))
240 err = -ENOENT;
241 else
242 typemap[type->proto] = NULL;
243 xfrm_state_unlock_afinfo(afinfo);
244 return err;
245}
246EXPORT_SYMBOL(xfrm_unregister_type);
247
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800248static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700249{
250 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800251 const struct xfrm_type **typemap;
252 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700253 int modload_attempted = 0;
254
255retry:
256 afinfo = xfrm_state_get_afinfo(family);
257 if (unlikely(afinfo == NULL))
258 return NULL;
259 typemap = afinfo->type_map;
260
261 type = typemap[proto];
262 if (unlikely(type && !try_module_get(type->owner)))
263 type = NULL;
264 if (!type && !modload_attempted) {
265 xfrm_state_put_afinfo(afinfo);
266 request_module("xfrm-type-%d-%d", family, proto);
267 modload_attempted = 1;
268 goto retry;
269 }
270
271 xfrm_state_put_afinfo(afinfo);
272 return type;
273}
274
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800275static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700276{
277 module_put(type->owner);
278}
279
280int xfrm_register_mode(struct xfrm_mode *mode, int family)
281{
282 struct xfrm_state_afinfo *afinfo;
283 struct xfrm_mode **modemap;
284 int err;
285
286 if (unlikely(mode->encap >= XFRM_MODE_MAX))
287 return -EINVAL;
288
289 afinfo = xfrm_state_lock_afinfo(family);
290 if (unlikely(afinfo == NULL))
291 return -EAFNOSUPPORT;
292
293 err = -EEXIST;
294 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700295 if (modemap[mode->encap])
296 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700297
Herbert Xu17c2a422007-10-17 21:33:12 -0700298 err = -ENOENT;
299 if (!try_module_get(afinfo->owner))
300 goto out;
301
302 mode->afinfo = afinfo;
303 modemap[mode->encap] = mode;
304 err = 0;
305
306out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700307 xfrm_state_unlock_afinfo(afinfo);
308 return err;
309}
310EXPORT_SYMBOL(xfrm_register_mode);
311
312int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
313{
314 struct xfrm_state_afinfo *afinfo;
315 struct xfrm_mode **modemap;
316 int err;
317
318 if (unlikely(mode->encap >= XFRM_MODE_MAX))
319 return -EINVAL;
320
321 afinfo = xfrm_state_lock_afinfo(family);
322 if (unlikely(afinfo == NULL))
323 return -EAFNOSUPPORT;
324
325 err = -ENOENT;
326 modemap = afinfo->mode_map;
327 if (likely(modemap[mode->encap] == mode)) {
328 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700329 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700330 err = 0;
331 }
332
333 xfrm_state_unlock_afinfo(afinfo);
334 return err;
335}
336EXPORT_SYMBOL(xfrm_unregister_mode);
337
338static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
339{
340 struct xfrm_state_afinfo *afinfo;
341 struct xfrm_mode *mode;
342 int modload_attempted = 0;
343
344 if (unlikely(encap >= XFRM_MODE_MAX))
345 return NULL;
346
347retry:
348 afinfo = xfrm_state_get_afinfo(family);
349 if (unlikely(afinfo == NULL))
350 return NULL;
351
352 mode = afinfo->mode_map[encap];
353 if (unlikely(mode && !try_module_get(mode->owner)))
354 mode = NULL;
355 if (!mode && !modload_attempted) {
356 xfrm_state_put_afinfo(afinfo);
357 request_module("xfrm-mode-%d-%d", family, encap);
358 modload_attempted = 1;
359 goto retry;
360 }
361
362 xfrm_state_put_afinfo(afinfo);
363 return mode;
364}
365
366static void xfrm_put_mode(struct xfrm_mode *mode)
367{
368 module_put(mode->owner);
369}
370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371static void xfrm_state_gc_destroy(struct xfrm_state *x)
372{
David S. Millera47f0ce2006-08-24 03:54:22 -0700373 del_timer_sync(&x->timer);
374 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800375 kfree(x->aalg);
376 kfree(x->ealg);
377 kfree(x->calg);
378 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700379 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700380 if (x->inner_mode)
381 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700382 if (x->inner_mode_iaf)
383 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700384 if (x->outer_mode)
385 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 if (x->type) {
387 x->type->destructor(x);
388 xfrm_put_type(x->type);
389 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800390 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 kfree(x);
392}
393
David Howellsc4028952006-11-22 14:57:56 +0000394static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
Herbert Xu12a169e2008-10-01 07:03:24 -0700396 struct xfrm_state *x;
397 struct hlist_node *entry, *tmp;
398 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700401 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 spin_unlock_bh(&xfrm_state_gc_lock);
403
Herbert Xu12a169e2008-10-01 07:03:24 -0700404 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 wake_up(&km_waitq);
408}
409
410static inline unsigned long make_jiffies(long secs)
411{
412 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
413 return MAX_SCHEDULE_TIMEOUT-1;
414 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900415 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
418static void xfrm_timer_handler(unsigned long data)
419{
420 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800421 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 long next = LONG_MAX;
423 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600424 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 spin_lock(&x->lock);
427 if (x->km.state == XFRM_STATE_DEAD)
428 goto out;
429 if (x->km.state == XFRM_STATE_EXPIRED)
430 goto expired;
431 if (x->lft.hard_add_expires_seconds) {
432 long tmo = x->lft.hard_add_expires_seconds +
433 x->curlft.add_time - now;
434 if (tmo <= 0)
435 goto expired;
436 if (tmo < next)
437 next = tmo;
438 }
439 if (x->lft.hard_use_expires_seconds) {
440 long tmo = x->lft.hard_use_expires_seconds +
441 (x->curlft.use_time ? : now) - now;
442 if (tmo <= 0)
443 goto expired;
444 if (tmo < next)
445 next = tmo;
446 }
447 if (x->km.dying)
448 goto resched;
449 if (x->lft.soft_add_expires_seconds) {
450 long tmo = x->lft.soft_add_expires_seconds +
451 x->curlft.add_time - now;
452 if (tmo <= 0)
453 warn = 1;
454 else if (tmo < next)
455 next = tmo;
456 }
457 if (x->lft.soft_use_expires_seconds) {
458 long tmo = x->lft.soft_use_expires_seconds +
459 (x->curlft.use_time ? : now) - now;
460 if (tmo <= 0)
461 warn = 1;
462 else if (tmo < next)
463 next = tmo;
464 }
465
Herbert Xu4666faa2005-06-18 22:43:22 -0700466 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800468 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700470 if (next != LONG_MAX)
471 mod_timer(&x->timer, jiffies + make_jiffies(next));
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 goto out;
474
475expired:
476 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
477 x->km.state = XFRM_STATE_EXPIRED;
478 wake_up(&km_waitq);
479 next = 2;
480 goto resched;
481 }
Joy Latten161a09e2006-11-27 13:11:54 -0600482
483 err = __xfrm_state_delete(x);
484 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800485 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Joy Lattenab5f5e82007-09-17 11:51:22 -0700487 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400488 audit_get_loginuid(current),
489 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491out:
492 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493}
494
David S. Miller0ac84752006-03-20 19:18:23 -0800495static void xfrm_replay_timer_handler(unsigned long data);
496
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800497struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
499 struct xfrm_state *x;
500
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700501 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800504 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 atomic_set(&x->refcnt, 1);
506 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700507 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700508 INIT_HLIST_NODE(&x->bydst);
509 INIT_HLIST_NODE(&x->bysrc);
510 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800511 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
512 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
513 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800514 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 x->lft.soft_byte_limit = XFRM_INF;
516 x->lft.soft_packet_limit = XFRM_INF;
517 x->lft.hard_byte_limit = XFRM_INF;
518 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800519 x->replay_maxage = 0;
520 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700521 x->inner_mode = NULL;
522 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 spin_lock_init(&x->lock);
524 }
525 return x;
526}
527EXPORT_SYMBOL(xfrm_state_alloc);
528
529void __xfrm_state_destroy(struct xfrm_state *x)
530{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700531 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700534 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 spin_unlock_bh(&xfrm_state_gc_lock);
536 schedule_work(&xfrm_state_gc_work);
537}
538EXPORT_SYMBOL(__xfrm_state_destroy);
539
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800540int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700542 int err = -ESRCH;
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (x->km.state != XFRM_STATE_DEAD) {
545 x->km.state = XFRM_STATE_DEAD;
546 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700547 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700548 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700549 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700550 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700551 hlist_del(&x->byspi);
David S. Millerf034b5d2006-08-24 03:08:07 -0700552 xfrm_state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 /* All xfrm_state objects are created by xfrm_state_alloc.
556 * The xfrm_state_alloc call gives a reference, and that
557 * is what we are dropping here.
558 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800559 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700560 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700562
563 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800565EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700569 int err;
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700572 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700574
575 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576}
577EXPORT_SYMBOL(xfrm_state_delete);
578
Joy Latten4aa2e622007-06-04 19:05:57 -0400579#ifdef CONFIG_SECURITY_NETWORK_XFRM
580static inline int
581xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
Joy Latten4aa2e622007-06-04 19:05:57 -0400583 int i, err = 0;
584
585 for (i = 0; i <= xfrm_state_hmask; i++) {
586 struct hlist_node *entry;
587 struct xfrm_state *x;
588
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800589 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400590 if (xfrm_id_proto_match(x->id.proto, proto) &&
591 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700592 xfrm_audit_state_delete(x, 0,
593 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400594 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700595 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400596 return err;
597 }
598 }
599 }
600
601 return err;
602}
603#else
604static inline int
605xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
606{
607 return 0;
608}
609#endif
610
611int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
612{
613 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400616 err = xfrm_state_flush_secctx_check(proto, audit_info);
617 if (err)
618 goto out;
619
Masahide NAKAMURAa9917c02006-08-31 15:14:32 -0700620 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700621 struct hlist_node *entry;
622 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800624 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700626 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 xfrm_state_hold(x);
628 spin_unlock_bh(&xfrm_state_lock);
629
Joy Latten161a09e2006-11-27 13:11:54 -0600630 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700631 xfrm_audit_state_delete(x, err ? 0 : 1,
632 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400633 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700634 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 xfrm_state_put(x);
636
637 spin_lock_bh(&xfrm_state_lock);
638 goto restart;
639 }
640 }
641 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400642 err = 0;
643
644out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 spin_unlock_bh(&xfrm_state_lock);
646 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400647 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648}
649EXPORT_SYMBOL(xfrm_state_flush);
650
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700651void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700652{
653 spin_lock_bh(&xfrm_state_lock);
654 si->sadcnt = xfrm_state_num;
655 si->sadhcnt = xfrm_state_hmask;
656 si->sadhmcnt = xfrm_state_hashmax;
657 spin_unlock_bh(&xfrm_state_lock);
658}
659EXPORT_SYMBOL(xfrm_sad_getinfo);
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661static int
662xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
663 struct xfrm_tmpl *tmpl,
664 xfrm_address_t *daddr, xfrm_address_t *saddr,
665 unsigned short family)
666{
667 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
668 if (!afinfo)
669 return -1;
670 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
671 xfrm_state_put_afinfo(afinfo);
672 return 0;
673}
674
Al Viroa94cfd12006-09-27 18:47:24 -0700675static 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 -0700676{
677 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
678 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700679 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700680
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800681 hlist_for_each_entry(x, entry, init_net.xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700682 if (x->props.family != family ||
683 x->id.spi != spi ||
684 x->id.proto != proto)
685 continue;
686
687 switch (family) {
688 case AF_INET:
689 if (x->id.daddr.a4 != daddr->a4)
690 continue;
691 break;
692 case AF_INET6:
693 if (!ipv6_addr_equal((struct in6_addr *)daddr,
694 (struct in6_addr *)
695 x->id.daddr.a6))
696 continue;
697 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700698 }
David S. Milleredcd5822006-08-24 00:42:45 -0700699
700 xfrm_state_hold(x);
701 return x;
702 }
703
704 return NULL;
705}
706
707static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
708{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700709 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700710 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700711 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700712
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800713 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700714 if (x->props.family != family ||
715 x->id.proto != proto)
716 continue;
717
718 switch (family) {
719 case AF_INET:
720 if (x->id.daddr.a4 != daddr->a4 ||
721 x->props.saddr.a4 != saddr->a4)
722 continue;
723 break;
724 case AF_INET6:
725 if (!ipv6_addr_equal((struct in6_addr *)daddr,
726 (struct in6_addr *)
727 x->id.daddr.a6) ||
728 !ipv6_addr_equal((struct in6_addr *)saddr,
729 (struct in6_addr *)
730 x->props.saddr.a6))
731 continue;
732 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700733 }
David S. Milleredcd5822006-08-24 00:42:45 -0700734
735 xfrm_state_hold(x);
736 return x;
737 }
738
739 return NULL;
740}
741
742static inline struct xfrm_state *
743__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
744{
745 if (use_spi)
746 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
747 x->id.proto, family);
748 else
749 return __xfrm_state_lookup_byaddr(&x->id.daddr,
750 &x->props.saddr,
751 x->id.proto, family);
752}
753
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700754static void xfrm_hash_grow_check(int have_hash_collision)
755{
756 if (have_hash_collision &&
757 (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
758 xfrm_state_num > xfrm_state_hmask)
759 schedule_work(&xfrm_hash_work);
760}
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900763xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 struct flowi *fl, struct xfrm_tmpl *tmpl,
765 struct xfrm_policy *pol, int *err,
766 unsigned short family)
767{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800768 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700769 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700770 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 int acquire_in_progress = 0;
772 int error = 0;
773 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900774
David S. Miller37b08e32008-09-02 20:14:15 -0700775 to_put = NULL;
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800778 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800779 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (x->props.family == family &&
781 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700782 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 xfrm_state_addr_check(x, daddr, saddr, family) &&
784 tmpl->mode == x->props.mode &&
785 tmpl->id.proto == x->id.proto &&
786 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
787 /* Resolution logic:
788 1. There is a valid state with matching selector.
789 Done.
790 2. Valid state with inappropriate selector. Skip.
791
792 Entering area of "sysdeps".
793
794 3. If state is not valid, selector is temporary,
795 it selects only session which triggered
796 previous resolution. Key manager will do
797 something to install a state with proper
798 selector.
799 */
800 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700801 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700802 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 continue;
804 if (!best ||
805 best->km.dying > x->km.dying ||
806 (best->km.dying == x->km.dying &&
807 best->curlft.add_time < x->curlft.add_time))
808 best = x;
809 } else if (x->km.state == XFRM_STATE_ACQ) {
810 acquire_in_progress = 1;
811 } else if (x->km.state == XFRM_STATE_ERROR ||
812 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700813 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700814 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 error = -ESRCH;
816 }
817 }
818 }
819
820 x = best;
821 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700822 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700823 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
824 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700825 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 error = -EEXIST;
827 goto out;
828 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800829 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 if (x == NULL) {
831 error = -ENOMEM;
832 goto out;
833 }
834 /* Initialize temporary selector matching only
835 * to current session. */
836 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
837
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700838 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
839 if (error) {
840 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700841 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700842 x = NULL;
843 goto out;
844 }
845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (km_query(x, tmpl, pol) == 0) {
847 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800848 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800849 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700850 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800851 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (x->id.spi) {
853 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800854 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
David S. Miller01e67d02007-05-25 00:41:38 -0700856 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
857 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 add_timer(&x->timer);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700859 xfrm_state_num++;
860 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 } else {
862 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700863 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 x = NULL;
865 error = -ESRCH;
866 }
867 }
868out:
869 if (x)
870 xfrm_state_hold(x);
871 else
872 *err = acquire_in_progress ? -EAGAIN : error;
873 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700874 if (to_put)
875 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 return x;
877}
878
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700879struct xfrm_state *
880xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
881 unsigned short family, u8 mode, u8 proto, u32 reqid)
882{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800883 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700884 struct xfrm_state *rx = NULL, *x = NULL;
885 struct hlist_node *entry;
886
887 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800888 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800889 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700890 if (x->props.family == family &&
891 x->props.reqid == reqid &&
892 !(x->props.flags & XFRM_STATE_WILDRECV) &&
893 xfrm_state_addr_check(x, daddr, saddr, family) &&
894 mode == x->props.mode &&
895 proto == x->id.proto &&
896 x->km.state == XFRM_STATE_VALID) {
897 rx = x;
898 break;
899 }
900 }
901
902 if (rx)
903 xfrm_state_hold(rx);
904 spin_unlock(&xfrm_state_lock);
905
906
907 return rx;
908}
909EXPORT_SYMBOL(xfrm_stateonly_find);
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911static void __xfrm_state_insert(struct xfrm_state *x)
912{
David S. Millera624c102006-08-24 03:24:33 -0700913 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
David S. Miller9d4a7062006-08-24 03:18:09 -0700915 x->genid = ++xfrm_state_genid;
916
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800917 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800918
David S. Millerc1969f22006-08-24 04:00:03 -0700919 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
920 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800921 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700923 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800924 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700926 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700927 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
928 x->props.family);
929
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800930 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700931 }
932
David S. Millera47f0ce2006-08-24 03:54:22 -0700933 mod_timer(&x->timer, jiffies + HZ);
934 if (x->replay_maxage)
935 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700938
939 xfrm_state_num++;
940
David S. Miller918049f2006-10-12 22:03:24 -0700941 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
David S. Millerc7f5ea32006-08-24 03:29:04 -0700944/* xfrm_state_lock is held */
945static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
946{
947 unsigned short family = xnew->props.family;
948 u32 reqid = xnew->props.reqid;
949 struct xfrm_state *x;
950 struct hlist_node *entry;
951 unsigned int h;
952
David S. Millerc1969f22006-08-24 04:00:03 -0700953 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800954 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700955 if (x->props.family == family &&
956 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700957 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
958 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700959 x->genid = xfrm_state_genid;
960 }
961}
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963void xfrm_state_insert(struct xfrm_state *x)
964{
965 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700966 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 __xfrm_state_insert(x);
968 spin_unlock_bh(&xfrm_state_lock);
969}
970EXPORT_SYMBOL(xfrm_state_insert);
971
David S. Miller27708342006-08-24 00:13:10 -0700972/* xfrm_state_lock is held */
973static 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)
974{
David S. Millerc1969f22006-08-24 04:00:03 -0700975 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700976 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700977 struct xfrm_state *x;
978
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800979 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700980 if (x->props.reqid != reqid ||
981 x->props.mode != mode ||
982 x->props.family != family ||
983 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700984 x->id.spi != 0 ||
985 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700986 continue;
987
988 switch (family) {
989 case AF_INET:
990 if (x->id.daddr.a4 != daddr->a4 ||
991 x->props.saddr.a4 != saddr->a4)
992 continue;
993 break;
994 case AF_INET6:
995 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
996 (struct in6_addr *)daddr) ||
997 !ipv6_addr_equal((struct in6_addr *)
998 x->props.saddr.a6,
999 (struct in6_addr *)saddr))
1000 continue;
1001 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001002 }
David S. Miller27708342006-08-24 00:13:10 -07001003
1004 xfrm_state_hold(x);
1005 return x;
1006 }
1007
1008 if (!create)
1009 return NULL;
1010
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001011 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001012 if (likely(x)) {
1013 switch (family) {
1014 case AF_INET:
1015 x->sel.daddr.a4 = daddr->a4;
1016 x->sel.saddr.a4 = saddr->a4;
1017 x->sel.prefixlen_d = 32;
1018 x->sel.prefixlen_s = 32;
1019 x->props.saddr.a4 = saddr->a4;
1020 x->id.daddr.a4 = daddr->a4;
1021 break;
1022
1023 case AF_INET6:
1024 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1025 (struct in6_addr *)daddr);
1026 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1027 (struct in6_addr *)saddr);
1028 x->sel.prefixlen_d = 128;
1029 x->sel.prefixlen_s = 128;
1030 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1031 (struct in6_addr *)saddr);
1032 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1033 (struct in6_addr *)daddr);
1034 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001035 }
David S. Miller27708342006-08-24 00:13:10 -07001036
1037 x->km.state = XFRM_STATE_ACQ;
1038 x->id.proto = proto;
1039 x->props.family = family;
1040 x->props.mode = mode;
1041 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001042 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001043 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001044 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001045 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001046 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001047 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001048 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001049 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001050
1051 xfrm_state_num++;
1052
1053 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001054 }
1055
1056 return x;
1057}
1058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1060
1061int xfrm_state_add(struct xfrm_state *x)
1062{
David S. Miller37b08e32008-09-02 20:14:15 -07001063 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 int family;
1065 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001066 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
David S. Miller37b08e32008-09-02 20:14:15 -07001070 to_put = NULL;
1071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 spin_lock_bh(&xfrm_state_lock);
1073
David S. Milleredcd5822006-08-24 00:42:45 -07001074 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001076 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 x1 = NULL;
1078 err = -EEXIST;
1079 goto out;
1080 }
1081
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001082 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001084 if (x1 && ((x1->id.proto != x->id.proto) ||
1085 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001086 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 x1 = NULL;
1088 }
1089 }
1090
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001091 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001092 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1093 x->id.proto,
1094 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
David S. Millerc7f5ea32006-08-24 03:29:04 -07001096 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 __xfrm_state_insert(x);
1098 err = 0;
1099
1100out:
1101 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 if (x1) {
1104 xfrm_state_delete(x1);
1105 xfrm_state_put(x1);
1106 }
1107
David S. Miller37b08e32008-09-02 20:14:15 -07001108 if (to_put)
1109 xfrm_state_put(to_put);
1110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return err;
1112}
1113EXPORT_SYMBOL(xfrm_state_add);
1114
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001115#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001116static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001117{
1118 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001119 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001120 if (!x)
1121 goto error;
1122
1123 memcpy(&x->id, &orig->id, sizeof(x->id));
1124 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1125 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1126 x->props.mode = orig->props.mode;
1127 x->props.replay_window = orig->props.replay_window;
1128 x->props.reqid = orig->props.reqid;
1129 x->props.family = orig->props.family;
1130 x->props.saddr = orig->props.saddr;
1131
1132 if (orig->aalg) {
1133 x->aalg = xfrm_algo_clone(orig->aalg);
1134 if (!x->aalg)
1135 goto error;
1136 }
1137 x->props.aalgo = orig->props.aalgo;
1138
1139 if (orig->ealg) {
1140 x->ealg = xfrm_algo_clone(orig->ealg);
1141 if (!x->ealg)
1142 goto error;
1143 }
1144 x->props.ealgo = orig->props.ealgo;
1145
1146 if (orig->calg) {
1147 x->calg = xfrm_algo_clone(orig->calg);
1148 if (!x->calg)
1149 goto error;
1150 }
1151 x->props.calgo = orig->props.calgo;
1152
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001153 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001154 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1155 if (!x->encap)
1156 goto error;
1157 }
1158
1159 if (orig->coaddr) {
1160 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1161 GFP_KERNEL);
1162 if (!x->coaddr)
1163 goto error;
1164 }
1165
1166 err = xfrm_init_state(x);
1167 if (err)
1168 goto error;
1169
1170 x->props.flags = orig->props.flags;
1171
1172 x->curlft.add_time = orig->curlft.add_time;
1173 x->km.state = orig->km.state;
1174 x->km.seq = orig->km.seq;
1175
1176 return x;
1177
1178 error:
1179 if (errp)
1180 *errp = err;
1181 if (x) {
1182 kfree(x->aalg);
1183 kfree(x->ealg);
1184 kfree(x->calg);
1185 kfree(x->encap);
1186 kfree(x->coaddr);
1187 }
1188 kfree(x);
1189 return NULL;
1190}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001191
1192/* xfrm_state_lock is held */
1193struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1194{
1195 unsigned int h;
1196 struct xfrm_state *x;
1197 struct hlist_node *entry;
1198
1199 if (m->reqid) {
1200 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1201 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001202 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001203 if (x->props.mode != m->mode ||
1204 x->id.proto != m->proto)
1205 continue;
1206 if (m->reqid && x->props.reqid != m->reqid)
1207 continue;
1208 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1209 m->old_family) ||
1210 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1211 m->old_family))
1212 continue;
1213 xfrm_state_hold(x);
1214 return x;
1215 }
1216 } else {
1217 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1218 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001219 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001220 if (x->props.mode != m->mode ||
1221 x->id.proto != m->proto)
1222 continue;
1223 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1224 m->old_family) ||
1225 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1226 m->old_family))
1227 continue;
1228 xfrm_state_hold(x);
1229 return x;
1230 }
1231 }
1232
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001233 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001234}
1235EXPORT_SYMBOL(xfrm_migrate_state_find);
1236
1237struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1238 struct xfrm_migrate *m)
1239{
1240 struct xfrm_state *xc;
1241 int err;
1242
1243 xc = xfrm_state_clone(x, &err);
1244 if (!xc)
1245 return NULL;
1246
1247 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1248 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1249
1250 /* add state */
1251 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1252 /* a care is needed when the destination address of the
1253 state is to be updated as it is a part of triplet */
1254 xfrm_state_insert(xc);
1255 } else {
1256 if ((err = xfrm_state_add(xc)) < 0)
1257 goto error;
1258 }
1259
1260 return xc;
1261error:
1262 kfree(xc);
1263 return NULL;
1264}
1265EXPORT_SYMBOL(xfrm_state_migrate);
1266#endif
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268int xfrm_state_update(struct xfrm_state *x)
1269{
David S. Miller37b08e32008-09-02 20:14:15 -07001270 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001272 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
David S. Miller37b08e32008-09-02 20:14:15 -07001274 to_put = NULL;
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001277 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279 err = -ESRCH;
1280 if (!x1)
1281 goto out;
1282
1283 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001284 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 err = -EEXIST;
1286 goto out;
1287 }
1288
1289 if (x1->km.state == XFRM_STATE_ACQ) {
1290 __xfrm_state_insert(x);
1291 x = NULL;
1292 }
1293 err = 0;
1294
1295out:
1296 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
David S. Miller37b08e32008-09-02 20:14:15 -07001298 if (to_put)
1299 xfrm_state_put(to_put);
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (err)
1302 return err;
1303
1304 if (!x) {
1305 xfrm_state_delete(x1);
1306 xfrm_state_put(x1);
1307 return 0;
1308 }
1309
1310 err = -EINVAL;
1311 spin_lock_bh(&x1->lock);
1312 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1313 if (x->encap && x1->encap)
1314 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001315 if (x->coaddr && x1->coaddr) {
1316 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1317 }
1318 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1319 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1321 x1->km.dying = 0;
1322
David S. Millera47f0ce2006-08-24 03:54:22 -07001323 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (x1->curlft.use_time)
1325 xfrm_state_check_expire(x1);
1326
1327 err = 0;
1328 }
1329 spin_unlock_bh(&x1->lock);
1330
1331 xfrm_state_put(x1);
1332
1333 return err;
1334}
1335EXPORT_SYMBOL(xfrm_state_update);
1336
1337int xfrm_state_check_expire(struct xfrm_state *x)
1338{
1339 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001340 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
1342 if (x->km.state != XFRM_STATE_VALID)
1343 return -EINVAL;
1344
1345 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1346 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001347 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001348 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return -EINVAL;
1350 }
1351
1352 if (!x->km.dying &&
1353 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001354 x->curlft.packets >= x->lft.soft_packet_limit)) {
1355 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001356 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 return 0;
1359}
1360EXPORT_SYMBOL(xfrm_state_check_expire);
1361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001363xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 unsigned short family)
1365{
1366 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001369 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return x;
1372}
1373EXPORT_SYMBOL(xfrm_state_lookup);
1374
1375struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001376xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1377 u8 proto, unsigned short family)
1378{
1379 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001380
1381 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001382 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001383 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001384 return x;
1385}
1386EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1387
1388struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001389xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1390 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 int create, unsigned short family)
1392{
1393 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001396 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 return x;
1400}
1401EXPORT_SYMBOL(xfrm_find_acq);
1402
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001403#ifdef CONFIG_XFRM_SUB_POLICY
1404int
1405xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1406 unsigned short family)
1407{
1408 int err = 0;
1409 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1410 if (!afinfo)
1411 return -EAFNOSUPPORT;
1412
1413 spin_lock_bh(&xfrm_state_lock);
1414 if (afinfo->tmpl_sort)
1415 err = afinfo->tmpl_sort(dst, src, n);
1416 spin_unlock_bh(&xfrm_state_lock);
1417 xfrm_state_put_afinfo(afinfo);
1418 return err;
1419}
1420EXPORT_SYMBOL(xfrm_tmpl_sort);
1421
1422int
1423xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1424 unsigned short family)
1425{
1426 int err = 0;
1427 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1428 if (!afinfo)
1429 return -EAFNOSUPPORT;
1430
1431 spin_lock_bh(&xfrm_state_lock);
1432 if (afinfo->state_sort)
1433 err = afinfo->state_sort(dst, src, n);
1434 spin_unlock_bh(&xfrm_state_lock);
1435 xfrm_state_put_afinfo(afinfo);
1436 return err;
1437}
1438EXPORT_SYMBOL(xfrm_state_sort);
1439#endif
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441/* Silly enough, but I'm lazy to build resolution list */
1442
1443static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1444{
1445 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
David S. Millerf034b5d2006-08-24 03:08:07 -07001447 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001448 struct hlist_node *entry;
1449 struct xfrm_state *x;
1450
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001451 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001452 if (x->km.seq == seq &&
1453 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 xfrm_state_hold(x);
1455 return x;
1456 }
1457 }
1458 }
1459 return NULL;
1460}
1461
1462struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1463{
1464 struct xfrm_state *x;
1465
1466 spin_lock_bh(&xfrm_state_lock);
1467 x = __xfrm_find_acq_byseq(seq);
1468 spin_unlock_bh(&xfrm_state_lock);
1469 return x;
1470}
1471EXPORT_SYMBOL(xfrm_find_acq_byseq);
1472
1473u32 xfrm_get_acqseq(void)
1474{
1475 u32 res;
1476 static u32 acqseq;
1477 static DEFINE_SPINLOCK(acqseq_lock);
1478
1479 spin_lock_bh(&acqseq_lock);
1480 res = (++acqseq ? : ++acqseq);
1481 spin_unlock_bh(&acqseq_lock);
1482 return res;
1483}
1484EXPORT_SYMBOL(xfrm_get_acqseq);
1485
Herbert Xu658b2192007-10-09 13:29:52 -07001486int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
David S. Millerf034b5d2006-08-24 03:08:07 -07001488 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001490 int err = -ENOENT;
1491 __be32 minspi = htonl(low);
1492 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
Herbert Xu658b2192007-10-09 13:29:52 -07001494 spin_lock_bh(&x->lock);
1495 if (x->km.state == XFRM_STATE_DEAD)
1496 goto unlock;
1497
1498 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001500 goto unlock;
1501
1502 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
1504 if (minspi == maxspi) {
1505 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1506 if (x0) {
1507 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001508 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 }
1510 x->id.spi = minspi;
1511 } else {
1512 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001513 for (h=0; h<high-low+1; h++) {
1514 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1516 if (x0 == NULL) {
1517 x->id.spi = htonl(spi);
1518 break;
1519 }
1520 xfrm_state_put(x0);
1521 }
1522 }
1523 if (x->id.spi) {
1524 spin_lock_bh(&xfrm_state_lock);
1525 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08001526 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001528
1529 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
Herbert Xu658b2192007-10-09 13:29:52 -07001531
1532unlock:
1533 spin_unlock_bh(&x->lock);
1534
1535 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536}
1537EXPORT_SYMBOL(xfrm_alloc_spi);
1538
Timo Teras4c563f72008-02-28 21:31:08 -08001539int xfrm_state_walk(struct xfrm_state_walk *walk,
1540 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 void *data)
1542{
Herbert Xu12a169e2008-10-01 07:03:24 -07001543 struct xfrm_state *state;
1544 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 int err = 0;
1546
Herbert Xu12a169e2008-10-01 07:03:24 -07001547 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001548 return 0;
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001551 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001552 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001553 else
1554 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001555 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001556 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001557 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001558 state = container_of(x, struct xfrm_state, km);
1559 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001560 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001561 err = func(state, walk->seq, data);
1562 if (err) {
1563 list_move_tail(&walk->all, &x->all);
1564 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001566 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001568 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 err = -ENOENT;
1570 goto out;
1571 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001572 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573out:
1574 spin_unlock_bh(&xfrm_state_lock);
1575 return err;
1576}
1577EXPORT_SYMBOL(xfrm_state_walk);
1578
Herbert Xu5c182452008-09-22 19:48:19 -07001579void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1580{
Herbert Xu12a169e2008-10-01 07:03:24 -07001581 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001582 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001583 walk->state = XFRM_STATE_DEAD;
1584 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001585}
1586EXPORT_SYMBOL(xfrm_state_walk_init);
1587
Herbert Xuabb81c42008-09-09 19:58:29 -07001588void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1589{
Herbert Xu12a169e2008-10-01 07:03:24 -07001590 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001591 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001592
Herbert Xu12a169e2008-10-01 07:03:24 -07001593 spin_lock_bh(&xfrm_state_lock);
1594 list_del(&walk->all);
1595 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001596}
1597EXPORT_SYMBOL(xfrm_state_walk_done);
1598
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001599
1600void xfrm_replay_notify(struct xfrm_state *x, int event)
1601{
1602 struct km_event c;
1603 /* we send notify messages in case
1604 * 1. we updated on of the sequence numbers, and the seqno difference
1605 * is at least x->replay_maxdiff, in this case we also update the
1606 * timeout of our timer function
1607 * 2. if x->replay_maxage has elapsed since last update,
1608 * and there were changes
1609 *
1610 * The state structure must be locked!
1611 */
1612
1613 switch (event) {
1614 case XFRM_REPLAY_UPDATE:
1615 if (x->replay_maxdiff &&
1616 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001617 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1618 if (x->xflags & XFRM_TIME_DEFER)
1619 event = XFRM_REPLAY_TIMEOUT;
1620 else
1621 return;
1622 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001623
1624 break;
1625
1626 case XFRM_REPLAY_TIMEOUT:
1627 if ((x->replay.seq == x->preplay.seq) &&
1628 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001629 (x->replay.oseq == x->preplay.oseq)) {
1630 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001631 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001632 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001633
1634 break;
1635 }
1636
1637 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1638 c.event = XFRM_MSG_NEWAE;
1639 c.data.aevent = event;
1640 km_state_notify(x, &c);
1641
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001642 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001643 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001644 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001645}
1646
1647static void xfrm_replay_timer_handler(unsigned long data)
1648{
1649 struct xfrm_state *x = (struct xfrm_state*)data;
1650
1651 spin_lock(&x->lock);
1652
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001653 if (x->km.state == XFRM_STATE_VALID) {
1654 if (xfrm_aevent_is_on())
1655 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1656 else
1657 x->xflags |= XFRM_TIME_DEFER;
1658 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001659
1660 spin_unlock(&x->lock);
1661}
1662
Paul Mooreafeb14b2007-12-21 14:58:11 -08001663int xfrm_replay_check(struct xfrm_state *x,
1664 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665{
1666 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001667 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
1669 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001670 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 if (likely(seq > x->replay.seq))
1673 return 0;
1674
1675 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001676 if (diff >= min_t(unsigned int, x->props.replay_window,
1677 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001679 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681
1682 if (x->replay.bitmap & (1U << diff)) {
1683 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001684 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
1686 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001687
1688err:
1689 xfrm_audit_state_replay(x, skb, net_seq);
1690 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Al Viro61f46272006-09-27 18:48:33 -07001693void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
1695 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001696 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
1698 if (seq > x->replay.seq) {
1699 diff = seq - x->replay.seq;
1700 if (diff < x->props.replay_window)
1701 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1702 else
1703 x->replay.bitmap = 1;
1704 x->replay.seq = seq;
1705 } else {
1706 diff = x->replay.seq - seq;
1707 x->replay.bitmap |= (1U << diff);
1708 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001709
1710 if (xfrm_aevent_is_on())
1711 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
Denis Chengdf018122007-12-07 00:51:11 -08001714static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715static DEFINE_RWLOCK(xfrm_km_lock);
1716
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001717void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 struct xfrm_mgr *km;
1720
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001721 read_lock(&xfrm_km_lock);
1722 list_for_each_entry(km, &xfrm_km_list, list)
1723 if (km->notify_policy)
1724 km->notify_policy(xp, dir, c);
1725 read_unlock(&xfrm_km_lock);
1726}
1727
1728void km_state_notify(struct xfrm_state *x, struct km_event *c)
1729{
1730 struct xfrm_mgr *km;
1731 read_lock(&xfrm_km_lock);
1732 list_for_each_entry(km, &xfrm_km_list, list)
1733 if (km->notify)
1734 km->notify(x, c);
1735 read_unlock(&xfrm_km_lock);
1736}
1737
1738EXPORT_SYMBOL(km_policy_notify);
1739EXPORT_SYMBOL(km_state_notify);
1740
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001741void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001742{
1743 struct km_event c;
1744
Herbert Xubf088672005-06-18 22:44:00 -07001745 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001746 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001747 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001748 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 if (hard)
1751 wake_up(&km_waitq);
1752}
1753
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001754EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001755/*
1756 * We send to all registered managers regardless of failure
1757 * We are happy with one success
1758*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001759int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001761 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 struct xfrm_mgr *km;
1763
1764 read_lock(&xfrm_km_lock);
1765 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001766 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1767 if (!acqret)
1768 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
1770 read_unlock(&xfrm_km_lock);
1771 return err;
1772}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001773EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Al Viro5d36b182006-11-08 00:24:06 -08001775int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776{
1777 int err = -EINVAL;
1778 struct xfrm_mgr *km;
1779
1780 read_lock(&xfrm_km_lock);
1781 list_for_each_entry(km, &xfrm_km_list, list) {
1782 if (km->new_mapping)
1783 err = km->new_mapping(x, ipaddr, sport);
1784 if (!err)
1785 break;
1786 }
1787 read_unlock(&xfrm_km_lock);
1788 return err;
1789}
1790EXPORT_SYMBOL(km_new_mapping);
1791
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001792void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001794 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
Herbert Xubf088672005-06-18 22:44:00 -07001796 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001797 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001798 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001799 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
1801 if (hard)
1802 wake_up(&km_waitq);
1803}
David S. Millera70fcb02006-03-20 19:18:52 -08001804EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001806#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001807int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001808 struct xfrm_migrate *m, int num_migrate,
1809 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001810{
1811 int err = -EINVAL;
1812 int ret;
1813 struct xfrm_mgr *km;
1814
1815 read_lock(&xfrm_km_lock);
1816 list_for_each_entry(km, &xfrm_km_list, list) {
1817 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001818 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001819 if (!ret)
1820 err = ret;
1821 }
1822 }
1823 read_unlock(&xfrm_km_lock);
1824 return err;
1825}
1826EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001827#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001828
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001829int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1830{
1831 int err = -EINVAL;
1832 int ret;
1833 struct xfrm_mgr *km;
1834
1835 read_lock(&xfrm_km_lock);
1836 list_for_each_entry(km, &xfrm_km_list, list) {
1837 if (km->report) {
1838 ret = km->report(proto, sel, addr);
1839 if (!ret)
1840 err = ret;
1841 }
1842 }
1843 read_unlock(&xfrm_km_lock);
1844 return err;
1845}
1846EXPORT_SYMBOL(km_report);
1847
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1849{
1850 int err;
1851 u8 *data;
1852 struct xfrm_mgr *km;
1853 struct xfrm_policy *pol = NULL;
1854
1855 if (optlen <= 0 || optlen > PAGE_SIZE)
1856 return -EMSGSIZE;
1857
1858 data = kmalloc(optlen, GFP_KERNEL);
1859 if (!data)
1860 return -ENOMEM;
1861
1862 err = -EFAULT;
1863 if (copy_from_user(data, optval, optlen))
1864 goto out;
1865
1866 err = -EINVAL;
1867 read_lock(&xfrm_km_lock);
1868 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001869 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 optlen, &err);
1871 if (err >= 0)
1872 break;
1873 }
1874 read_unlock(&xfrm_km_lock);
1875
1876 if (err >= 0) {
1877 xfrm_sk_policy_insert(sk, err, pol);
1878 xfrm_pol_put(pol);
1879 err = 0;
1880 }
1881
1882out:
1883 kfree(data);
1884 return err;
1885}
1886EXPORT_SYMBOL(xfrm_user_policy);
1887
1888int xfrm_register_km(struct xfrm_mgr *km)
1889{
1890 write_lock_bh(&xfrm_km_lock);
1891 list_add_tail(&km->list, &xfrm_km_list);
1892 write_unlock_bh(&xfrm_km_lock);
1893 return 0;
1894}
1895EXPORT_SYMBOL(xfrm_register_km);
1896
1897int xfrm_unregister_km(struct xfrm_mgr *km)
1898{
1899 write_lock_bh(&xfrm_km_lock);
1900 list_del(&km->list);
1901 write_unlock_bh(&xfrm_km_lock);
1902 return 0;
1903}
1904EXPORT_SYMBOL(xfrm_unregister_km);
1905
1906int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1907{
1908 int err = 0;
1909 if (unlikely(afinfo == NULL))
1910 return -EINVAL;
1911 if (unlikely(afinfo->family >= NPROTO))
1912 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001913 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1915 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001916 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001918 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 return err;
1920}
1921EXPORT_SYMBOL(xfrm_state_register_afinfo);
1922
1923int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1924{
1925 int err = 0;
1926 if (unlikely(afinfo == NULL))
1927 return -EINVAL;
1928 if (unlikely(afinfo->family >= NPROTO))
1929 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001930 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1932 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1933 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001934 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001937 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 return err;
1939}
1940EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1941
Herbert Xu17c2a422007-10-17 21:33:12 -07001942static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944 struct xfrm_state_afinfo *afinfo;
1945 if (unlikely(family >= NPROTO))
1946 return NULL;
1947 read_lock(&xfrm_state_afinfo_lock);
1948 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001949 if (unlikely(!afinfo))
1950 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 return afinfo;
1952}
1953
Herbert Xu17c2a422007-10-17 21:33:12 -07001954static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001955 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956{
Herbert Xu546be242006-05-27 23:03:58 -07001957 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958}
1959
1960/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1961void xfrm_state_delete_tunnel(struct xfrm_state *x)
1962{
1963 if (x->tunnel) {
1964 struct xfrm_state *t = x->tunnel;
1965
1966 if (atomic_read(&t->tunnel_users) == 2)
1967 xfrm_state_delete(t);
1968 atomic_dec(&t->tunnel_users);
1969 xfrm_state_put(t);
1970 x->tunnel = NULL;
1971 }
1972}
1973EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1974
1975int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1976{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001977 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
Patrick McHardyc5c25232007-04-09 11:47:18 -07001979 spin_lock_bh(&x->lock);
1980 if (x->km.state == XFRM_STATE_VALID &&
1981 x->type && x->type->get_mtu)
1982 res = x->type->get_mtu(x, mtu);
1983 else
Patrick McHardy28121612007-06-18 22:30:15 -07001984 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001985 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 return res;
1987}
1988
Herbert Xu72cb6962005-06-20 13:18:08 -07001989int xfrm_init_state(struct xfrm_state *x)
1990{
Herbert Xud094cd82005-06-20 13:19:41 -07001991 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001992 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001993 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001994 int err;
1995
Herbert Xud094cd82005-06-20 13:19:41 -07001996 err = -EAFNOSUPPORT;
1997 afinfo = xfrm_state_get_afinfo(family);
1998 if (!afinfo)
1999 goto error;
2000
2001 err = 0;
2002 if (afinfo->init_flags)
2003 err = afinfo->init_flags(x);
2004
2005 xfrm_state_put_afinfo(afinfo);
2006
2007 if (err)
2008 goto error;
2009
2010 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002011
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002012 if (x->sel.family != AF_UNSPEC) {
2013 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2014 if (inner_mode == NULL)
2015 goto error;
2016
2017 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2018 family != x->sel.family) {
2019 xfrm_put_mode(inner_mode);
2020 goto error;
2021 }
2022
2023 x->inner_mode = inner_mode;
2024 } else {
2025 struct xfrm_mode *inner_mode_iaf;
2026
2027 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2028 if (inner_mode == NULL)
2029 goto error;
2030
2031 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2032 xfrm_put_mode(inner_mode);
2033 goto error;
2034 }
2035
2036 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2037 if (inner_mode_iaf == NULL)
2038 goto error;
2039
2040 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2041 xfrm_put_mode(inner_mode_iaf);
2042 goto error;
2043 }
2044
2045 if (x->props.family == AF_INET) {
2046 x->inner_mode = inner_mode;
2047 x->inner_mode_iaf = inner_mode_iaf;
2048 } else {
2049 x->inner_mode = inner_mode_iaf;
2050 x->inner_mode_iaf = inner_mode;
2051 }
2052 }
Herbert Xu13996372007-10-17 21:35:51 -07002053
Herbert Xud094cd82005-06-20 13:19:41 -07002054 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002055 if (x->type == NULL)
2056 goto error;
2057
2058 err = x->type->init_state(x);
2059 if (err)
2060 goto error;
2061
Herbert Xu13996372007-10-17 21:35:51 -07002062 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2063 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002064 goto error;
2065
Herbert Xu72cb6962005-06-20 13:18:08 -07002066 x->km.state = XFRM_STATE_VALID;
2067
2068error:
2069 return err;
2070}
2071
2072EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002073
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002074int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
David S. Millerf034b5d2006-08-24 03:08:07 -07002076 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002078 INIT_LIST_HEAD(&net->xfrm.state_all);
2079
David S. Millerf034b5d2006-08-24 03:08:07 -07002080 sz = sizeof(struct hlist_head) * 8;
2081
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002082 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2083 if (!net->xfrm.state_bydst)
2084 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002085 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2086 if (!net->xfrm.state_bysrc)
2087 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002088 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2089 if (!net->xfrm.state_byspi)
2090 goto out_byspi;
David S. Millerf034b5d2006-08-24 03:08:07 -07002091 xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
2092
David Howellsc4028952006-11-22 14:57:56 +00002093 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002094 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002095
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002096out_byspi:
2097 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002098out_bysrc:
2099 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002100out_bydst:
2101 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002102}
2103
2104void xfrm_state_fini(struct net *net)
2105{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002106 unsigned int sz;
2107
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002108 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002109
2110 sz = (xfrm_state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002111 WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2112 xfrm_hash_free(net->xfrm.state_byspi, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002113 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2114 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002115 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2116 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117}
2118
Joy Lattenab5f5e82007-09-17 11:51:22 -07002119#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002120static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2121 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002122{
Paul Moore68277ac2007-12-20 20:49:33 -08002123 struct xfrm_sec_ctx *ctx = x->security;
2124 u32 spi = ntohl(x->id.spi);
2125
2126 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002127 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002128 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002129
2130 switch(x->props.family) {
2131 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002132 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2133 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002134 break;
2135 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002136 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002137 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002138 break;
2139 }
Paul Moore68277ac2007-12-20 20:49:33 -08002140
2141 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002142}
2143
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002144static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2145 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002146{
2147 struct iphdr *iph4;
2148 struct ipv6hdr *iph6;
2149
2150 switch (family) {
2151 case AF_INET:
2152 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002153 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2154 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002155 break;
2156 case AF_INET6:
2157 iph6 = ipv6_hdr(skb);
2158 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002159 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002160 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002161 iph6->flow_lbl[0] & 0x0f,
2162 iph6->flow_lbl[1],
2163 iph6->flow_lbl[2]);
2164 break;
2165 }
2166}
2167
Paul Moore68277ac2007-12-20 20:49:33 -08002168void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002169 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002170{
2171 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002172
Paul Mooreafeb14b2007-12-21 14:58:11 -08002173 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002174 if (audit_buf == NULL)
2175 return;
Eric Paris25323862008-04-18 10:09:25 -04002176 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002177 xfrm_audit_helper_sainfo(x, audit_buf);
2178 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002179 audit_log_end(audit_buf);
2180}
2181EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2182
Paul Moore68277ac2007-12-20 20:49:33 -08002183void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002184 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002185{
2186 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002187
Paul Mooreafeb14b2007-12-21 14:58:11 -08002188 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002189 if (audit_buf == NULL)
2190 return;
Eric Paris25323862008-04-18 10:09:25 -04002191 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002192 xfrm_audit_helper_sainfo(x, audit_buf);
2193 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002194 audit_log_end(audit_buf);
2195}
2196EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002197
2198void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2199 struct sk_buff *skb)
2200{
2201 struct audit_buffer *audit_buf;
2202 u32 spi;
2203
2204 audit_buf = xfrm_audit_start("SA-replay-overflow");
2205 if (audit_buf == NULL)
2206 return;
2207 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2208 /* don't record the sequence number because it's inherent in this kind
2209 * of audit message */
2210 spi = ntohl(x->id.spi);
2211 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2212 audit_log_end(audit_buf);
2213}
2214EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2215
2216static void xfrm_audit_state_replay(struct xfrm_state *x,
2217 struct sk_buff *skb, __be32 net_seq)
2218{
2219 struct audit_buffer *audit_buf;
2220 u32 spi;
2221
2222 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2223 if (audit_buf == NULL)
2224 return;
2225 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2226 spi = ntohl(x->id.spi);
2227 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2228 spi, spi, ntohl(net_seq));
2229 audit_log_end(audit_buf);
2230}
2231
2232void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2233{
2234 struct audit_buffer *audit_buf;
2235
2236 audit_buf = xfrm_audit_start("SA-notfound");
2237 if (audit_buf == NULL)
2238 return;
2239 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2240 audit_log_end(audit_buf);
2241}
2242EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2243
2244void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2245 __be32 net_spi, __be32 net_seq)
2246{
2247 struct audit_buffer *audit_buf;
2248 u32 spi;
2249
2250 audit_buf = xfrm_audit_start("SA-notfound");
2251 if (audit_buf == NULL)
2252 return;
2253 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2254 spi = ntohl(net_spi);
2255 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2256 spi, spi, ntohl(net_seq));
2257 audit_log_end(audit_buf);
2258}
2259EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2260
2261void xfrm_audit_state_icvfail(struct xfrm_state *x,
2262 struct sk_buff *skb, u8 proto)
2263{
2264 struct audit_buffer *audit_buf;
2265 __be32 net_spi;
2266 __be32 net_seq;
2267
2268 audit_buf = xfrm_audit_start("SA-icv-failure");
2269 if (audit_buf == NULL)
2270 return;
2271 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2272 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2273 u32 spi = ntohl(net_spi);
2274 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2275 spi, spi, ntohl(net_seq));
2276 }
2277 audit_log_end(audit_buf);
2278}
2279EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002280#endif /* CONFIG_AUDITSYSCALL */