blob: 864a97477ae55d353e3218f5fe4d5e1af23899bd [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_hashmax __read_mostly = 1 * 1024 * 1024;
David S. Miller9d4a7062006-08-24 03:18:09 -070048static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Herbert Xu17c2a422007-10-17 21:33:12 -070050static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
51static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
52
Paul Mooreafeb14b2007-12-21 14:58:11 -080053#ifdef CONFIG_AUDITSYSCALL
54static void xfrm_audit_state_replay(struct xfrm_state *x,
55 struct sk_buff *skb, __be32 net_seq);
56#else
57#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
58#endif /* CONFIG_AUDITSYSCALL */
59
David S. Millerc1969f22006-08-24 04:00:03 -070060static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
61 xfrm_address_t *saddr,
62 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070063 unsigned short family)
64{
Alexey Dobriyan529983e2008-11-25 17:18:12 -080065 return __xfrm_dst_hash(daddr, saddr, reqid, family, init_net.xfrm.state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070066}
67
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070068static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
69 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070070 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070071{
Alexey Dobriyan529983e2008-11-25 17:18:12 -080072 return __xfrm_src_hash(daddr, saddr, family, init_net.xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070073}
74
David S. Miller2575b652006-08-24 03:26:44 -070075static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070076xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070077{
Alexey Dobriyan529983e2008-11-25 17:18:12 -080078 return __xfrm_spi_hash(daddr, spi, proto, family, init_net.xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070079}
80
David S. Millerf034b5d2006-08-24 03:08:07 -070081static void xfrm_hash_transfer(struct hlist_head *list,
82 struct hlist_head *ndsttable,
83 struct hlist_head *nsrctable,
84 struct hlist_head *nspitable,
85 unsigned int nhashmask)
86{
87 struct hlist_node *entry, *tmp;
88 struct xfrm_state *x;
89
90 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
91 unsigned int h;
92
David S. Millerc1969f22006-08-24 04:00:03 -070093 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
94 x->props.reqid, x->props.family,
95 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070096 hlist_add_head(&x->bydst, ndsttable+h);
97
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070098 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
99 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700100 nhashmask);
101 hlist_add_head(&x->bysrc, nsrctable+h);
102
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700103 if (x->id.spi) {
104 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
105 x->id.proto, x->props.family,
106 nhashmask);
107 hlist_add_head(&x->byspi, nspitable+h);
108 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700109 }
110}
111
Alexey Dobriyan63082732008-11-25 17:19:07 -0800112static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
David S. Millerf034b5d2006-08-24 03:08:07 -0700113{
Alexey Dobriyan63082732008-11-25 17:19:07 -0800114 return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
David S. Millerf034b5d2006-08-24 03:08:07 -0700115}
116
117static DEFINE_MUTEX(hash_resize_mutex);
118
Alexey Dobriyan63082732008-11-25 17:19:07 -0800119static void xfrm_hash_resize(struct work_struct *work)
David S. Millerf034b5d2006-08-24 03:08:07 -0700120{
Alexey Dobriyan63082732008-11-25 17:19:07 -0800121 struct net *net = container_of(work, struct net, xfrm.state_hash_work);
David S. Millerf034b5d2006-08-24 03:08:07 -0700122 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
123 unsigned long nsize, osize;
124 unsigned int nhashmask, ohashmask;
125 int i;
126
127 mutex_lock(&hash_resize_mutex);
128
Alexey Dobriyan63082732008-11-25 17:19:07 -0800129 nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
David S. Miller44e36b42006-08-24 04:50:50 -0700130 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700131 if (!ndst)
132 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700133 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700134 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700135 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700136 goto out_unlock;
137 }
David S. Miller44e36b42006-08-24 04:50:50 -0700138 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700139 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700140 xfrm_hash_free(ndst, nsize);
141 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700142 goto out_unlock;
143 }
144
145 spin_lock_bh(&xfrm_state_lock);
146
147 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
Alexey Dobriyan63082732008-11-25 17:19:07 -0800148 for (i = net->xfrm.state_hmask; i >= 0; i--)
149 xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700150 nhashmask);
151
Alexey Dobriyan63082732008-11-25 17:19:07 -0800152 odst = net->xfrm.state_bydst;
153 osrc = net->xfrm.state_bysrc;
154 ospi = net->xfrm.state_byspi;
155 ohashmask = net->xfrm.state_hmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700156
Alexey Dobriyan63082732008-11-25 17:19:07 -0800157 net->xfrm.state_bydst = ndst;
158 net->xfrm.state_bysrc = nsrc;
159 net->xfrm.state_byspi = nspi;
160 net->xfrm.state_hmask = nhashmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700161
162 spin_unlock_bh(&xfrm_state_lock);
163
164 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700165 xfrm_hash_free(odst, osize);
166 xfrm_hash_free(osrc, osize);
167 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700168
169out_unlock:
170 mutex_unlock(&hash_resize_mutex);
171}
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173DECLARE_WAIT_QUEUE_HEAD(km_waitq);
174EXPORT_SYMBOL(km_waitq);
175
176static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
177static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
178
179static struct work_struct xfrm_state_gc_work;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static DEFINE_SPINLOCK(xfrm_state_gc_lock);
181
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800182int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800184int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800185void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700187static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
188{
189 struct xfrm_state_afinfo *afinfo;
190 if (unlikely(family >= NPROTO))
191 return NULL;
192 write_lock_bh(&xfrm_state_afinfo_lock);
193 afinfo = xfrm_state_afinfo[family];
194 if (unlikely(!afinfo))
195 write_unlock_bh(&xfrm_state_afinfo_lock);
196 return afinfo;
197}
198
199static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800200 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700201{
202 write_unlock_bh(&xfrm_state_afinfo_lock);
203}
204
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800205int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700206{
207 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800208 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700209 int err = 0;
210
211 if (unlikely(afinfo == NULL))
212 return -EAFNOSUPPORT;
213 typemap = afinfo->type_map;
214
215 if (likely(typemap[type->proto] == NULL))
216 typemap[type->proto] = type;
217 else
218 err = -EEXIST;
219 xfrm_state_unlock_afinfo(afinfo);
220 return err;
221}
222EXPORT_SYMBOL(xfrm_register_type);
223
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800224int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700225{
226 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800227 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700228 int err = 0;
229
230 if (unlikely(afinfo == NULL))
231 return -EAFNOSUPPORT;
232 typemap = afinfo->type_map;
233
234 if (unlikely(typemap[type->proto] != type))
235 err = -ENOENT;
236 else
237 typemap[type->proto] = NULL;
238 xfrm_state_unlock_afinfo(afinfo);
239 return err;
240}
241EXPORT_SYMBOL(xfrm_unregister_type);
242
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800243static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700244{
245 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800246 const struct xfrm_type **typemap;
247 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700248 int modload_attempted = 0;
249
250retry:
251 afinfo = xfrm_state_get_afinfo(family);
252 if (unlikely(afinfo == NULL))
253 return NULL;
254 typemap = afinfo->type_map;
255
256 type = typemap[proto];
257 if (unlikely(type && !try_module_get(type->owner)))
258 type = NULL;
259 if (!type && !modload_attempted) {
260 xfrm_state_put_afinfo(afinfo);
261 request_module("xfrm-type-%d-%d", family, proto);
262 modload_attempted = 1;
263 goto retry;
264 }
265
266 xfrm_state_put_afinfo(afinfo);
267 return type;
268}
269
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800270static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700271{
272 module_put(type->owner);
273}
274
275int xfrm_register_mode(struct xfrm_mode *mode, int family)
276{
277 struct xfrm_state_afinfo *afinfo;
278 struct xfrm_mode **modemap;
279 int err;
280
281 if (unlikely(mode->encap >= XFRM_MODE_MAX))
282 return -EINVAL;
283
284 afinfo = xfrm_state_lock_afinfo(family);
285 if (unlikely(afinfo == NULL))
286 return -EAFNOSUPPORT;
287
288 err = -EEXIST;
289 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700290 if (modemap[mode->encap])
291 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700292
Herbert Xu17c2a422007-10-17 21:33:12 -0700293 err = -ENOENT;
294 if (!try_module_get(afinfo->owner))
295 goto out;
296
297 mode->afinfo = afinfo;
298 modemap[mode->encap] = mode;
299 err = 0;
300
301out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700302 xfrm_state_unlock_afinfo(afinfo);
303 return err;
304}
305EXPORT_SYMBOL(xfrm_register_mode);
306
307int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
308{
309 struct xfrm_state_afinfo *afinfo;
310 struct xfrm_mode **modemap;
311 int err;
312
313 if (unlikely(mode->encap >= XFRM_MODE_MAX))
314 return -EINVAL;
315
316 afinfo = xfrm_state_lock_afinfo(family);
317 if (unlikely(afinfo == NULL))
318 return -EAFNOSUPPORT;
319
320 err = -ENOENT;
321 modemap = afinfo->mode_map;
322 if (likely(modemap[mode->encap] == mode)) {
323 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700324 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700325 err = 0;
326 }
327
328 xfrm_state_unlock_afinfo(afinfo);
329 return err;
330}
331EXPORT_SYMBOL(xfrm_unregister_mode);
332
333static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
334{
335 struct xfrm_state_afinfo *afinfo;
336 struct xfrm_mode *mode;
337 int modload_attempted = 0;
338
339 if (unlikely(encap >= XFRM_MODE_MAX))
340 return NULL;
341
342retry:
343 afinfo = xfrm_state_get_afinfo(family);
344 if (unlikely(afinfo == NULL))
345 return NULL;
346
347 mode = afinfo->mode_map[encap];
348 if (unlikely(mode && !try_module_get(mode->owner)))
349 mode = NULL;
350 if (!mode && !modload_attempted) {
351 xfrm_state_put_afinfo(afinfo);
352 request_module("xfrm-mode-%d-%d", family, encap);
353 modload_attempted = 1;
354 goto retry;
355 }
356
357 xfrm_state_put_afinfo(afinfo);
358 return mode;
359}
360
361static void xfrm_put_mode(struct xfrm_mode *mode)
362{
363 module_put(mode->owner);
364}
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366static void xfrm_state_gc_destroy(struct xfrm_state *x)
367{
David S. Millera47f0ce2006-08-24 03:54:22 -0700368 del_timer_sync(&x->timer);
369 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800370 kfree(x->aalg);
371 kfree(x->ealg);
372 kfree(x->calg);
373 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700374 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700375 if (x->inner_mode)
376 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700377 if (x->inner_mode_iaf)
378 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700379 if (x->outer_mode)
380 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 if (x->type) {
382 x->type->destructor(x);
383 xfrm_put_type(x->type);
384 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800385 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 kfree(x);
387}
388
David Howellsc4028952006-11-22 14:57:56 +0000389static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
Herbert Xu12a169e2008-10-01 07:03:24 -0700391 struct xfrm_state *x;
392 struct hlist_node *entry, *tmp;
393 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 spin_lock_bh(&xfrm_state_gc_lock);
Alexey Dobriyanb8a0ae22008-11-25 17:20:11 -0800396 hlist_move_list(&init_net.xfrm.state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 spin_unlock_bh(&xfrm_state_gc_lock);
398
Herbert Xu12a169e2008-10-01 07:03:24 -0700399 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 wake_up(&km_waitq);
403}
404
405static inline unsigned long make_jiffies(long secs)
406{
407 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
408 return MAX_SCHEDULE_TIMEOUT-1;
409 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900410 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
413static void xfrm_timer_handler(unsigned long data)
414{
415 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800416 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 long next = LONG_MAX;
418 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600419 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 spin_lock(&x->lock);
422 if (x->km.state == XFRM_STATE_DEAD)
423 goto out;
424 if (x->km.state == XFRM_STATE_EXPIRED)
425 goto expired;
426 if (x->lft.hard_add_expires_seconds) {
427 long tmo = x->lft.hard_add_expires_seconds +
428 x->curlft.add_time - now;
429 if (tmo <= 0)
430 goto expired;
431 if (tmo < next)
432 next = tmo;
433 }
434 if (x->lft.hard_use_expires_seconds) {
435 long tmo = x->lft.hard_use_expires_seconds +
436 (x->curlft.use_time ? : now) - now;
437 if (tmo <= 0)
438 goto expired;
439 if (tmo < next)
440 next = tmo;
441 }
442 if (x->km.dying)
443 goto resched;
444 if (x->lft.soft_add_expires_seconds) {
445 long tmo = x->lft.soft_add_expires_seconds +
446 x->curlft.add_time - now;
447 if (tmo <= 0)
448 warn = 1;
449 else if (tmo < next)
450 next = tmo;
451 }
452 if (x->lft.soft_use_expires_seconds) {
453 long tmo = x->lft.soft_use_expires_seconds +
454 (x->curlft.use_time ? : now) - now;
455 if (tmo <= 0)
456 warn = 1;
457 else if (tmo < next)
458 next = tmo;
459 }
460
Herbert Xu4666faa2005-06-18 22:43:22 -0700461 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800463 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700465 if (next != LONG_MAX)
466 mod_timer(&x->timer, jiffies + make_jiffies(next));
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 goto out;
469
470expired:
471 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
472 x->km.state = XFRM_STATE_EXPIRED;
473 wake_up(&km_waitq);
474 next = 2;
475 goto resched;
476 }
Joy Latten161a09e2006-11-27 13:11:54 -0600477
478 err = __xfrm_state_delete(x);
479 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800480 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Joy Lattenab5f5e82007-09-17 11:51:22 -0700482 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400483 audit_get_loginuid(current),
484 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486out:
487 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
David S. Miller0ac84752006-03-20 19:18:23 -0800490static void xfrm_replay_timer_handler(unsigned long data);
491
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800492struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
494 struct xfrm_state *x;
495
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700496 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800499 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 atomic_set(&x->refcnt, 1);
501 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700502 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700503 INIT_HLIST_NODE(&x->bydst);
504 INIT_HLIST_NODE(&x->bysrc);
505 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800506 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
507 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
508 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800509 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 x->lft.soft_byte_limit = XFRM_INF;
511 x->lft.soft_packet_limit = XFRM_INF;
512 x->lft.hard_byte_limit = XFRM_INF;
513 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800514 x->replay_maxage = 0;
515 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700516 x->inner_mode = NULL;
517 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 spin_lock_init(&x->lock);
519 }
520 return x;
521}
522EXPORT_SYMBOL(xfrm_state_alloc);
523
524void __xfrm_state_destroy(struct xfrm_state *x)
525{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700526 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
528 spin_lock_bh(&xfrm_state_gc_lock);
Alexey Dobriyanb8a0ae22008-11-25 17:20:11 -0800529 hlist_add_head(&x->gclist, &init_net.xfrm.state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 spin_unlock_bh(&xfrm_state_gc_lock);
531 schedule_work(&xfrm_state_gc_work);
532}
533EXPORT_SYMBOL(__xfrm_state_destroy);
534
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800535int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700537 int err = -ESRCH;
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 if (x->km.state != XFRM_STATE_DEAD) {
540 x->km.state = XFRM_STATE_DEAD;
541 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700542 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700543 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700544 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700545 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700546 hlist_del(&x->byspi);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800547 init_net.xfrm.state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 /* All xfrm_state objects are created by xfrm_state_alloc.
551 * The xfrm_state_alloc call gives a reference, and that
552 * is what we are dropping here.
553 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800554 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700555 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700557
558 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800560EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700562int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700564 int err;
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700569
570 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571}
572EXPORT_SYMBOL(xfrm_state_delete);
573
Joy Latten4aa2e622007-06-04 19:05:57 -0400574#ifdef CONFIG_SECURITY_NETWORK_XFRM
575static inline int
576xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
Joy Latten4aa2e622007-06-04 19:05:57 -0400578 int i, err = 0;
579
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800580 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400581 struct hlist_node *entry;
582 struct xfrm_state *x;
583
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800584 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400585 if (xfrm_id_proto_match(x->id.proto, proto) &&
586 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700587 xfrm_audit_state_delete(x, 0,
588 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400589 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700590 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400591 return err;
592 }
593 }
594 }
595
596 return err;
597}
598#else
599static inline int
600xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
601{
602 return 0;
603}
604#endif
605
606int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
607{
608 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400611 err = xfrm_state_flush_secctx_check(proto, audit_info);
612 if (err)
613 goto out;
614
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800615 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700616 struct hlist_node *entry;
617 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800619 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700621 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 xfrm_state_hold(x);
623 spin_unlock_bh(&xfrm_state_lock);
624
Joy Latten161a09e2006-11-27 13:11:54 -0600625 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700626 xfrm_audit_state_delete(x, err ? 0 : 1,
627 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400628 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700629 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 xfrm_state_put(x);
631
632 spin_lock_bh(&xfrm_state_lock);
633 goto restart;
634 }
635 }
636 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400637 err = 0;
638
639out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 spin_unlock_bh(&xfrm_state_lock);
641 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400642 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644EXPORT_SYMBOL(xfrm_state_flush);
645
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700646void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700647{
648 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800649 si->sadcnt = init_net.xfrm.state_num;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800650 si->sadhcnt = init_net.xfrm.state_hmask;
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700651 si->sadhmcnt = xfrm_state_hashmax;
652 spin_unlock_bh(&xfrm_state_lock);
653}
654EXPORT_SYMBOL(xfrm_sad_getinfo);
655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656static int
657xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
658 struct xfrm_tmpl *tmpl,
659 xfrm_address_t *daddr, xfrm_address_t *saddr,
660 unsigned short family)
661{
662 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
663 if (!afinfo)
664 return -1;
665 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
666 xfrm_state_put_afinfo(afinfo);
667 return 0;
668}
669
Al Viroa94cfd12006-09-27 18:47:24 -0700670static 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 -0700671{
672 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
673 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700674 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700675
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800676 hlist_for_each_entry(x, entry, init_net.xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700677 if (x->props.family != family ||
678 x->id.spi != spi ||
679 x->id.proto != proto)
680 continue;
681
682 switch (family) {
683 case AF_INET:
684 if (x->id.daddr.a4 != daddr->a4)
685 continue;
686 break;
687 case AF_INET6:
688 if (!ipv6_addr_equal((struct in6_addr *)daddr,
689 (struct in6_addr *)
690 x->id.daddr.a6))
691 continue;
692 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700693 }
David S. Milleredcd5822006-08-24 00:42:45 -0700694
695 xfrm_state_hold(x);
696 return x;
697 }
698
699 return NULL;
700}
701
702static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
703{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700704 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700705 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700706 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700707
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800708 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700709 if (x->props.family != family ||
710 x->id.proto != proto)
711 continue;
712
713 switch (family) {
714 case AF_INET:
715 if (x->id.daddr.a4 != daddr->a4 ||
716 x->props.saddr.a4 != saddr->a4)
717 continue;
718 break;
719 case AF_INET6:
720 if (!ipv6_addr_equal((struct in6_addr *)daddr,
721 (struct in6_addr *)
722 x->id.daddr.a6) ||
723 !ipv6_addr_equal((struct in6_addr *)saddr,
724 (struct in6_addr *)
725 x->props.saddr.a6))
726 continue;
727 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700728 }
David S. Milleredcd5822006-08-24 00:42:45 -0700729
730 xfrm_state_hold(x);
731 return x;
732 }
733
734 return NULL;
735}
736
737static inline struct xfrm_state *
738__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
739{
740 if (use_spi)
741 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
742 x->id.proto, family);
743 else
744 return __xfrm_state_lookup_byaddr(&x->id.daddr,
745 &x->props.saddr,
746 x->id.proto, family);
747}
748
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700749static void xfrm_hash_grow_check(int have_hash_collision)
750{
751 if (have_hash_collision &&
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800752 (init_net.xfrm.state_hmask + 1) < xfrm_state_hashmax &&
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800753 init_net.xfrm.state_num > init_net.xfrm.state_hmask)
Alexey Dobriyan63082732008-11-25 17:19:07 -0800754 schedule_work(&init_net.xfrm.state_hash_work);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900758xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 struct flowi *fl, struct xfrm_tmpl *tmpl,
760 struct xfrm_policy *pol, int *err,
761 unsigned short family)
762{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800763 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700764 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700765 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 int acquire_in_progress = 0;
767 int error = 0;
768 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900769
David S. Miller37b08e32008-09-02 20:14:15 -0700770 to_put = NULL;
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800773 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800774 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (x->props.family == family &&
776 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700777 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 xfrm_state_addr_check(x, daddr, saddr, family) &&
779 tmpl->mode == x->props.mode &&
780 tmpl->id.proto == x->id.proto &&
781 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
782 /* Resolution logic:
783 1. There is a valid state with matching selector.
784 Done.
785 2. Valid state with inappropriate selector. Skip.
786
787 Entering area of "sysdeps".
788
789 3. If state is not valid, selector is temporary,
790 it selects only session which triggered
791 previous resolution. Key manager will do
792 something to install a state with proper
793 selector.
794 */
795 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700796 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700797 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 continue;
799 if (!best ||
800 best->km.dying > x->km.dying ||
801 (best->km.dying == x->km.dying &&
802 best->curlft.add_time < x->curlft.add_time))
803 best = x;
804 } else if (x->km.state == XFRM_STATE_ACQ) {
805 acquire_in_progress = 1;
806 } else if (x->km.state == XFRM_STATE_ERROR ||
807 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700808 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700809 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 error = -ESRCH;
811 }
812 }
813 }
814
815 x = best;
816 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700817 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700818 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
819 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700820 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 error = -EEXIST;
822 goto out;
823 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800824 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (x == NULL) {
826 error = -ENOMEM;
827 goto out;
828 }
829 /* Initialize temporary selector matching only
830 * to current session. */
831 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
832
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700833 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
834 if (error) {
835 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700836 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700837 x = NULL;
838 goto out;
839 }
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (km_query(x, tmpl, pol) == 0) {
842 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800843 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800844 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700845 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800846 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (x->id.spi) {
848 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800849 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
David S. Miller01e67d02007-05-25 00:41:38 -0700851 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
852 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 add_timer(&x->timer);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800854 init_net.xfrm.state_num++;
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700855 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 } else {
857 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700858 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 x = NULL;
860 error = -ESRCH;
861 }
862 }
863out:
864 if (x)
865 xfrm_state_hold(x);
866 else
867 *err = acquire_in_progress ? -EAGAIN : error;
868 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700869 if (to_put)
870 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return x;
872}
873
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700874struct xfrm_state *
875xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
876 unsigned short family, u8 mode, u8 proto, u32 reqid)
877{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800878 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700879 struct xfrm_state *rx = NULL, *x = NULL;
880 struct hlist_node *entry;
881
882 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800883 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800884 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700885 if (x->props.family == family &&
886 x->props.reqid == reqid &&
887 !(x->props.flags & XFRM_STATE_WILDRECV) &&
888 xfrm_state_addr_check(x, daddr, saddr, family) &&
889 mode == x->props.mode &&
890 proto == x->id.proto &&
891 x->km.state == XFRM_STATE_VALID) {
892 rx = x;
893 break;
894 }
895 }
896
897 if (rx)
898 xfrm_state_hold(rx);
899 spin_unlock(&xfrm_state_lock);
900
901
902 return rx;
903}
904EXPORT_SYMBOL(xfrm_stateonly_find);
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906static void __xfrm_state_insert(struct xfrm_state *x)
907{
David S. Millera624c102006-08-24 03:24:33 -0700908 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
David S. Miller9d4a7062006-08-24 03:18:09 -0700910 x->genid = ++xfrm_state_genid;
911
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800912 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800913
David S. Millerc1969f22006-08-24 04:00:03 -0700914 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
915 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800916 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700918 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800919 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700921 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700922 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
923 x->props.family);
924
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800925 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700926 }
927
David S. Millera47f0ce2006-08-24 03:54:22 -0700928 mod_timer(&x->timer, jiffies + HZ);
929 if (x->replay_maxage)
930 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700933
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800934 init_net.xfrm.state_num++;
David S. Millerf034b5d2006-08-24 03:08:07 -0700935
David S. Miller918049f2006-10-12 22:03:24 -0700936 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937}
938
David S. Millerc7f5ea32006-08-24 03:29:04 -0700939/* xfrm_state_lock is held */
940static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
941{
942 unsigned short family = xnew->props.family;
943 u32 reqid = xnew->props.reqid;
944 struct xfrm_state *x;
945 struct hlist_node *entry;
946 unsigned int h;
947
David S. Millerc1969f22006-08-24 04:00:03 -0700948 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800949 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700950 if (x->props.family == family &&
951 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700952 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
953 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700954 x->genid = xfrm_state_genid;
955 }
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958void xfrm_state_insert(struct xfrm_state *x)
959{
960 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700961 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 __xfrm_state_insert(x);
963 spin_unlock_bh(&xfrm_state_lock);
964}
965EXPORT_SYMBOL(xfrm_state_insert);
966
David S. Miller27708342006-08-24 00:13:10 -0700967/* xfrm_state_lock is held */
968static 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)
969{
David S. Millerc1969f22006-08-24 04:00:03 -0700970 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700971 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700972 struct xfrm_state *x;
973
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800974 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700975 if (x->props.reqid != reqid ||
976 x->props.mode != mode ||
977 x->props.family != family ||
978 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700979 x->id.spi != 0 ||
980 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700981 continue;
982
983 switch (family) {
984 case AF_INET:
985 if (x->id.daddr.a4 != daddr->a4 ||
986 x->props.saddr.a4 != saddr->a4)
987 continue;
988 break;
989 case AF_INET6:
990 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
991 (struct in6_addr *)daddr) ||
992 !ipv6_addr_equal((struct in6_addr *)
993 x->props.saddr.a6,
994 (struct in6_addr *)saddr))
995 continue;
996 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700997 }
David S. Miller27708342006-08-24 00:13:10 -0700998
999 xfrm_state_hold(x);
1000 return x;
1001 }
1002
1003 if (!create)
1004 return NULL;
1005
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001006 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001007 if (likely(x)) {
1008 switch (family) {
1009 case AF_INET:
1010 x->sel.daddr.a4 = daddr->a4;
1011 x->sel.saddr.a4 = saddr->a4;
1012 x->sel.prefixlen_d = 32;
1013 x->sel.prefixlen_s = 32;
1014 x->props.saddr.a4 = saddr->a4;
1015 x->id.daddr.a4 = daddr->a4;
1016 break;
1017
1018 case AF_INET6:
1019 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1020 (struct in6_addr *)daddr);
1021 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1022 (struct in6_addr *)saddr);
1023 x->sel.prefixlen_d = 128;
1024 x->sel.prefixlen_s = 128;
1025 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1026 (struct in6_addr *)saddr);
1027 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1028 (struct in6_addr *)daddr);
1029 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001030 }
David S. Miller27708342006-08-24 00:13:10 -07001031
1032 x->km.state = XFRM_STATE_ACQ;
1033 x->id.proto = proto;
1034 x->props.family = family;
1035 x->props.mode = mode;
1036 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001037 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001038 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001039 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001040 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001041 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001042 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001043 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001044 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001045
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08001046 init_net.xfrm.state_num++;
David S. Miller918049f2006-10-12 22:03:24 -07001047
1048 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001049 }
1050
1051 return x;
1052}
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1055
1056int xfrm_state_add(struct xfrm_state *x)
1057{
David S. Miller37b08e32008-09-02 20:14:15 -07001058 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 int family;
1060 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001061 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
David S. Miller37b08e32008-09-02 20:14:15 -07001065 to_put = NULL;
1066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 spin_lock_bh(&xfrm_state_lock);
1068
David S. Milleredcd5822006-08-24 00:42:45 -07001069 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001071 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 x1 = NULL;
1073 err = -EEXIST;
1074 goto out;
1075 }
1076
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001077 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001079 if (x1 && ((x1->id.proto != x->id.proto) ||
1080 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001081 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 x1 = NULL;
1083 }
1084 }
1085
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001086 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001087 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1088 x->id.proto,
1089 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
David S. Millerc7f5ea32006-08-24 03:29:04 -07001091 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 __xfrm_state_insert(x);
1093 err = 0;
1094
1095out:
1096 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 if (x1) {
1099 xfrm_state_delete(x1);
1100 xfrm_state_put(x1);
1101 }
1102
David S. Miller37b08e32008-09-02 20:14:15 -07001103 if (to_put)
1104 xfrm_state_put(to_put);
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 return err;
1107}
1108EXPORT_SYMBOL(xfrm_state_add);
1109
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001110#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001111static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001112{
1113 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001114 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001115 if (!x)
1116 goto error;
1117
1118 memcpy(&x->id, &orig->id, sizeof(x->id));
1119 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1120 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1121 x->props.mode = orig->props.mode;
1122 x->props.replay_window = orig->props.replay_window;
1123 x->props.reqid = orig->props.reqid;
1124 x->props.family = orig->props.family;
1125 x->props.saddr = orig->props.saddr;
1126
1127 if (orig->aalg) {
1128 x->aalg = xfrm_algo_clone(orig->aalg);
1129 if (!x->aalg)
1130 goto error;
1131 }
1132 x->props.aalgo = orig->props.aalgo;
1133
1134 if (orig->ealg) {
1135 x->ealg = xfrm_algo_clone(orig->ealg);
1136 if (!x->ealg)
1137 goto error;
1138 }
1139 x->props.ealgo = orig->props.ealgo;
1140
1141 if (orig->calg) {
1142 x->calg = xfrm_algo_clone(orig->calg);
1143 if (!x->calg)
1144 goto error;
1145 }
1146 x->props.calgo = orig->props.calgo;
1147
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001148 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001149 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1150 if (!x->encap)
1151 goto error;
1152 }
1153
1154 if (orig->coaddr) {
1155 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1156 GFP_KERNEL);
1157 if (!x->coaddr)
1158 goto error;
1159 }
1160
1161 err = xfrm_init_state(x);
1162 if (err)
1163 goto error;
1164
1165 x->props.flags = orig->props.flags;
1166
1167 x->curlft.add_time = orig->curlft.add_time;
1168 x->km.state = orig->km.state;
1169 x->km.seq = orig->km.seq;
1170
1171 return x;
1172
1173 error:
1174 if (errp)
1175 *errp = err;
1176 if (x) {
1177 kfree(x->aalg);
1178 kfree(x->ealg);
1179 kfree(x->calg);
1180 kfree(x->encap);
1181 kfree(x->coaddr);
1182 }
1183 kfree(x);
1184 return NULL;
1185}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001186
1187/* xfrm_state_lock is held */
1188struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1189{
1190 unsigned int h;
1191 struct xfrm_state *x;
1192 struct hlist_node *entry;
1193
1194 if (m->reqid) {
1195 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1196 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001197 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001198 if (x->props.mode != m->mode ||
1199 x->id.proto != m->proto)
1200 continue;
1201 if (m->reqid && x->props.reqid != m->reqid)
1202 continue;
1203 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1204 m->old_family) ||
1205 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1206 m->old_family))
1207 continue;
1208 xfrm_state_hold(x);
1209 return x;
1210 }
1211 } else {
1212 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1213 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001214 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001215 if (x->props.mode != m->mode ||
1216 x->id.proto != m->proto)
1217 continue;
1218 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1219 m->old_family) ||
1220 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1221 m->old_family))
1222 continue;
1223 xfrm_state_hold(x);
1224 return x;
1225 }
1226 }
1227
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001228 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001229}
1230EXPORT_SYMBOL(xfrm_migrate_state_find);
1231
1232struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1233 struct xfrm_migrate *m)
1234{
1235 struct xfrm_state *xc;
1236 int err;
1237
1238 xc = xfrm_state_clone(x, &err);
1239 if (!xc)
1240 return NULL;
1241
1242 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1243 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1244
1245 /* add state */
1246 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1247 /* a care is needed when the destination address of the
1248 state is to be updated as it is a part of triplet */
1249 xfrm_state_insert(xc);
1250 } else {
1251 if ((err = xfrm_state_add(xc)) < 0)
1252 goto error;
1253 }
1254
1255 return xc;
1256error:
1257 kfree(xc);
1258 return NULL;
1259}
1260EXPORT_SYMBOL(xfrm_state_migrate);
1261#endif
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263int xfrm_state_update(struct xfrm_state *x)
1264{
David S. Miller37b08e32008-09-02 20:14:15 -07001265 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001267 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
David S. Miller37b08e32008-09-02 20:14:15 -07001269 to_put = NULL;
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001272 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
1274 err = -ESRCH;
1275 if (!x1)
1276 goto out;
1277
1278 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001279 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 err = -EEXIST;
1281 goto out;
1282 }
1283
1284 if (x1->km.state == XFRM_STATE_ACQ) {
1285 __xfrm_state_insert(x);
1286 x = NULL;
1287 }
1288 err = 0;
1289
1290out:
1291 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
David S. Miller37b08e32008-09-02 20:14:15 -07001293 if (to_put)
1294 xfrm_state_put(to_put);
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (err)
1297 return err;
1298
1299 if (!x) {
1300 xfrm_state_delete(x1);
1301 xfrm_state_put(x1);
1302 return 0;
1303 }
1304
1305 err = -EINVAL;
1306 spin_lock_bh(&x1->lock);
1307 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1308 if (x->encap && x1->encap)
1309 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001310 if (x->coaddr && x1->coaddr) {
1311 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1312 }
1313 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1314 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1316 x1->km.dying = 0;
1317
David S. Millera47f0ce2006-08-24 03:54:22 -07001318 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (x1->curlft.use_time)
1320 xfrm_state_check_expire(x1);
1321
1322 err = 0;
1323 }
1324 spin_unlock_bh(&x1->lock);
1325
1326 xfrm_state_put(x1);
1327
1328 return err;
1329}
1330EXPORT_SYMBOL(xfrm_state_update);
1331
1332int xfrm_state_check_expire(struct xfrm_state *x)
1333{
1334 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001335 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 if (x->km.state != XFRM_STATE_VALID)
1338 return -EINVAL;
1339
1340 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1341 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001342 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001343 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 return -EINVAL;
1345 }
1346
1347 if (!x->km.dying &&
1348 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001349 x->curlft.packets >= x->lft.soft_packet_limit)) {
1350 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001351 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 return 0;
1354}
1355EXPORT_SYMBOL(xfrm_state_check_expire);
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001358xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 unsigned short family)
1360{
1361 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001364 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 return x;
1367}
1368EXPORT_SYMBOL(xfrm_state_lookup);
1369
1370struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001371xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1372 u8 proto, unsigned short family)
1373{
1374 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001375
1376 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001377 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001378 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001379 return x;
1380}
1381EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1382
1383struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001384xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1385 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 int create, unsigned short family)
1387{
1388 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001391 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 return x;
1395}
1396EXPORT_SYMBOL(xfrm_find_acq);
1397
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001398#ifdef CONFIG_XFRM_SUB_POLICY
1399int
1400xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1401 unsigned short family)
1402{
1403 int err = 0;
1404 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1405 if (!afinfo)
1406 return -EAFNOSUPPORT;
1407
1408 spin_lock_bh(&xfrm_state_lock);
1409 if (afinfo->tmpl_sort)
1410 err = afinfo->tmpl_sort(dst, src, n);
1411 spin_unlock_bh(&xfrm_state_lock);
1412 xfrm_state_put_afinfo(afinfo);
1413 return err;
1414}
1415EXPORT_SYMBOL(xfrm_tmpl_sort);
1416
1417int
1418xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1419 unsigned short family)
1420{
1421 int err = 0;
1422 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1423 if (!afinfo)
1424 return -EAFNOSUPPORT;
1425
1426 spin_lock_bh(&xfrm_state_lock);
1427 if (afinfo->state_sort)
1428 err = afinfo->state_sort(dst, src, n);
1429 spin_unlock_bh(&xfrm_state_lock);
1430 xfrm_state_put_afinfo(afinfo);
1431 return err;
1432}
1433EXPORT_SYMBOL(xfrm_state_sort);
1434#endif
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436/* Silly enough, but I'm lazy to build resolution list */
1437
1438static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1439{
1440 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Alexey Dobriyan529983e2008-11-25 17:18:12 -08001442 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001443 struct hlist_node *entry;
1444 struct xfrm_state *x;
1445
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001446 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001447 if (x->km.seq == seq &&
1448 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 xfrm_state_hold(x);
1450 return x;
1451 }
1452 }
1453 }
1454 return NULL;
1455}
1456
1457struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1458{
1459 struct xfrm_state *x;
1460
1461 spin_lock_bh(&xfrm_state_lock);
1462 x = __xfrm_find_acq_byseq(seq);
1463 spin_unlock_bh(&xfrm_state_lock);
1464 return x;
1465}
1466EXPORT_SYMBOL(xfrm_find_acq_byseq);
1467
1468u32 xfrm_get_acqseq(void)
1469{
1470 u32 res;
1471 static u32 acqseq;
1472 static DEFINE_SPINLOCK(acqseq_lock);
1473
1474 spin_lock_bh(&acqseq_lock);
1475 res = (++acqseq ? : ++acqseq);
1476 spin_unlock_bh(&acqseq_lock);
1477 return res;
1478}
1479EXPORT_SYMBOL(xfrm_get_acqseq);
1480
Herbert Xu658b2192007-10-09 13:29:52 -07001481int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
David S. Millerf034b5d2006-08-24 03:08:07 -07001483 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001485 int err = -ENOENT;
1486 __be32 minspi = htonl(low);
1487 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
Herbert Xu658b2192007-10-09 13:29:52 -07001489 spin_lock_bh(&x->lock);
1490 if (x->km.state == XFRM_STATE_DEAD)
1491 goto unlock;
1492
1493 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001495 goto unlock;
1496
1497 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 if (minspi == maxspi) {
1500 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1501 if (x0) {
1502 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001503 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 }
1505 x->id.spi = minspi;
1506 } else {
1507 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001508 for (h=0; h<high-low+1; h++) {
1509 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1511 if (x0 == NULL) {
1512 x->id.spi = htonl(spi);
1513 break;
1514 }
1515 xfrm_state_put(x0);
1516 }
1517 }
1518 if (x->id.spi) {
1519 spin_lock_bh(&xfrm_state_lock);
1520 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08001521 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001523
1524 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 }
Herbert Xu658b2192007-10-09 13:29:52 -07001526
1527unlock:
1528 spin_unlock_bh(&x->lock);
1529
1530 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531}
1532EXPORT_SYMBOL(xfrm_alloc_spi);
1533
Timo Teras4c563f72008-02-28 21:31:08 -08001534int xfrm_state_walk(struct xfrm_state_walk *walk,
1535 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 void *data)
1537{
Herbert Xu12a169e2008-10-01 07:03:24 -07001538 struct xfrm_state *state;
1539 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 int err = 0;
1541
Herbert Xu12a169e2008-10-01 07:03:24 -07001542 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001543 return 0;
1544
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001546 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001547 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001548 else
1549 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001550 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001551 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001552 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001553 state = container_of(x, struct xfrm_state, km);
1554 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001555 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001556 err = func(state, walk->seq, data);
1557 if (err) {
1558 list_move_tail(&walk->all, &x->all);
1559 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001561 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001563 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 err = -ENOENT;
1565 goto out;
1566 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001567 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568out:
1569 spin_unlock_bh(&xfrm_state_lock);
1570 return err;
1571}
1572EXPORT_SYMBOL(xfrm_state_walk);
1573
Herbert Xu5c182452008-09-22 19:48:19 -07001574void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1575{
Herbert Xu12a169e2008-10-01 07:03:24 -07001576 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001577 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001578 walk->state = XFRM_STATE_DEAD;
1579 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001580}
1581EXPORT_SYMBOL(xfrm_state_walk_init);
1582
Herbert Xuabb81c42008-09-09 19:58:29 -07001583void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1584{
Herbert Xu12a169e2008-10-01 07:03:24 -07001585 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001586 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001587
Herbert Xu12a169e2008-10-01 07:03:24 -07001588 spin_lock_bh(&xfrm_state_lock);
1589 list_del(&walk->all);
1590 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001591}
1592EXPORT_SYMBOL(xfrm_state_walk_done);
1593
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001594
1595void xfrm_replay_notify(struct xfrm_state *x, int event)
1596{
1597 struct km_event c;
1598 /* we send notify messages in case
1599 * 1. we updated on of the sequence numbers, and the seqno difference
1600 * is at least x->replay_maxdiff, in this case we also update the
1601 * timeout of our timer function
1602 * 2. if x->replay_maxage has elapsed since last update,
1603 * and there were changes
1604 *
1605 * The state structure must be locked!
1606 */
1607
1608 switch (event) {
1609 case XFRM_REPLAY_UPDATE:
1610 if (x->replay_maxdiff &&
1611 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001612 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1613 if (x->xflags & XFRM_TIME_DEFER)
1614 event = XFRM_REPLAY_TIMEOUT;
1615 else
1616 return;
1617 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001618
1619 break;
1620
1621 case XFRM_REPLAY_TIMEOUT:
1622 if ((x->replay.seq == x->preplay.seq) &&
1623 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001624 (x->replay.oseq == x->preplay.oseq)) {
1625 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001626 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001627 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001628
1629 break;
1630 }
1631
1632 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1633 c.event = XFRM_MSG_NEWAE;
1634 c.data.aevent = event;
1635 km_state_notify(x, &c);
1636
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001637 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001638 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001639 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001640}
1641
1642static void xfrm_replay_timer_handler(unsigned long data)
1643{
1644 struct xfrm_state *x = (struct xfrm_state*)data;
1645
1646 spin_lock(&x->lock);
1647
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001648 if (x->km.state == XFRM_STATE_VALID) {
1649 if (xfrm_aevent_is_on())
1650 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1651 else
1652 x->xflags |= XFRM_TIME_DEFER;
1653 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001654
1655 spin_unlock(&x->lock);
1656}
1657
Paul Mooreafeb14b2007-12-21 14:58:11 -08001658int xfrm_replay_check(struct xfrm_state *x,
1659 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
1661 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001662 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001665 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 if (likely(seq > x->replay.seq))
1668 return 0;
1669
1670 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001671 if (diff >= min_t(unsigned int, x->props.replay_window,
1672 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001674 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 }
1676
1677 if (x->replay.bitmap & (1U << diff)) {
1678 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001679 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001682
1683err:
1684 xfrm_audit_state_replay(x, skb, net_seq);
1685 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Al Viro61f46272006-09-27 18:48:33 -07001688void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689{
1690 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001691 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 if (seq > x->replay.seq) {
1694 diff = seq - x->replay.seq;
1695 if (diff < x->props.replay_window)
1696 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1697 else
1698 x->replay.bitmap = 1;
1699 x->replay.seq = seq;
1700 } else {
1701 diff = x->replay.seq - seq;
1702 x->replay.bitmap |= (1U << diff);
1703 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001704
1705 if (xfrm_aevent_is_on())
1706 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Denis Chengdf018122007-12-07 00:51:11 -08001709static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710static DEFINE_RWLOCK(xfrm_km_lock);
1711
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001712void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
1714 struct xfrm_mgr *km;
1715
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001716 read_lock(&xfrm_km_lock);
1717 list_for_each_entry(km, &xfrm_km_list, list)
1718 if (km->notify_policy)
1719 km->notify_policy(xp, dir, c);
1720 read_unlock(&xfrm_km_lock);
1721}
1722
1723void km_state_notify(struct xfrm_state *x, struct km_event *c)
1724{
1725 struct xfrm_mgr *km;
1726 read_lock(&xfrm_km_lock);
1727 list_for_each_entry(km, &xfrm_km_list, list)
1728 if (km->notify)
1729 km->notify(x, c);
1730 read_unlock(&xfrm_km_lock);
1731}
1732
1733EXPORT_SYMBOL(km_policy_notify);
1734EXPORT_SYMBOL(km_state_notify);
1735
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001736void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001737{
1738 struct km_event c;
1739
Herbert Xubf088672005-06-18 22:44:00 -07001740 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001741 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001742 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001743 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
1745 if (hard)
1746 wake_up(&km_waitq);
1747}
1748
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001749EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001750/*
1751 * We send to all registered managers regardless of failure
1752 * We are happy with one success
1753*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001754int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001756 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 struct xfrm_mgr *km;
1758
1759 read_lock(&xfrm_km_lock);
1760 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001761 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1762 if (!acqret)
1763 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 }
1765 read_unlock(&xfrm_km_lock);
1766 return err;
1767}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001768EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Al Viro5d36b182006-11-08 00:24:06 -08001770int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
1772 int err = -EINVAL;
1773 struct xfrm_mgr *km;
1774
1775 read_lock(&xfrm_km_lock);
1776 list_for_each_entry(km, &xfrm_km_list, list) {
1777 if (km->new_mapping)
1778 err = km->new_mapping(x, ipaddr, sport);
1779 if (!err)
1780 break;
1781 }
1782 read_unlock(&xfrm_km_lock);
1783 return err;
1784}
1785EXPORT_SYMBOL(km_new_mapping);
1786
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001787void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001789 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Herbert Xubf088672005-06-18 22:44:00 -07001791 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001792 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001793 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001794 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
1796 if (hard)
1797 wake_up(&km_waitq);
1798}
David S. Millera70fcb02006-03-20 19:18:52 -08001799EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001801#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001802int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001803 struct xfrm_migrate *m, int num_migrate,
1804 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001805{
1806 int err = -EINVAL;
1807 int ret;
1808 struct xfrm_mgr *km;
1809
1810 read_lock(&xfrm_km_lock);
1811 list_for_each_entry(km, &xfrm_km_list, list) {
1812 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001813 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001814 if (!ret)
1815 err = ret;
1816 }
1817 }
1818 read_unlock(&xfrm_km_lock);
1819 return err;
1820}
1821EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001822#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001823
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001824int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1825{
1826 int err = -EINVAL;
1827 int ret;
1828 struct xfrm_mgr *km;
1829
1830 read_lock(&xfrm_km_lock);
1831 list_for_each_entry(km, &xfrm_km_list, list) {
1832 if (km->report) {
1833 ret = km->report(proto, sel, addr);
1834 if (!ret)
1835 err = ret;
1836 }
1837 }
1838 read_unlock(&xfrm_km_lock);
1839 return err;
1840}
1841EXPORT_SYMBOL(km_report);
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1844{
1845 int err;
1846 u8 *data;
1847 struct xfrm_mgr *km;
1848 struct xfrm_policy *pol = NULL;
1849
1850 if (optlen <= 0 || optlen > PAGE_SIZE)
1851 return -EMSGSIZE;
1852
1853 data = kmalloc(optlen, GFP_KERNEL);
1854 if (!data)
1855 return -ENOMEM;
1856
1857 err = -EFAULT;
1858 if (copy_from_user(data, optval, optlen))
1859 goto out;
1860
1861 err = -EINVAL;
1862 read_lock(&xfrm_km_lock);
1863 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001864 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 optlen, &err);
1866 if (err >= 0)
1867 break;
1868 }
1869 read_unlock(&xfrm_km_lock);
1870
1871 if (err >= 0) {
1872 xfrm_sk_policy_insert(sk, err, pol);
1873 xfrm_pol_put(pol);
1874 err = 0;
1875 }
1876
1877out:
1878 kfree(data);
1879 return err;
1880}
1881EXPORT_SYMBOL(xfrm_user_policy);
1882
1883int xfrm_register_km(struct xfrm_mgr *km)
1884{
1885 write_lock_bh(&xfrm_km_lock);
1886 list_add_tail(&km->list, &xfrm_km_list);
1887 write_unlock_bh(&xfrm_km_lock);
1888 return 0;
1889}
1890EXPORT_SYMBOL(xfrm_register_km);
1891
1892int xfrm_unregister_km(struct xfrm_mgr *km)
1893{
1894 write_lock_bh(&xfrm_km_lock);
1895 list_del(&km->list);
1896 write_unlock_bh(&xfrm_km_lock);
1897 return 0;
1898}
1899EXPORT_SYMBOL(xfrm_unregister_km);
1900
1901int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1902{
1903 int err = 0;
1904 if (unlikely(afinfo == NULL))
1905 return -EINVAL;
1906 if (unlikely(afinfo->family >= NPROTO))
1907 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001908 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1910 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001911 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001913 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 return err;
1915}
1916EXPORT_SYMBOL(xfrm_state_register_afinfo);
1917
1918int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1919{
1920 int err = 0;
1921 if (unlikely(afinfo == NULL))
1922 return -EINVAL;
1923 if (unlikely(afinfo->family >= NPROTO))
1924 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001925 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1927 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1928 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001929 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001932 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 return err;
1934}
1935EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1936
Herbert Xu17c2a422007-10-17 21:33:12 -07001937static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938{
1939 struct xfrm_state_afinfo *afinfo;
1940 if (unlikely(family >= NPROTO))
1941 return NULL;
1942 read_lock(&xfrm_state_afinfo_lock);
1943 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001944 if (unlikely(!afinfo))
1945 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 return afinfo;
1947}
1948
Herbert Xu17c2a422007-10-17 21:33:12 -07001949static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001950 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951{
Herbert Xu546be242006-05-27 23:03:58 -07001952 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953}
1954
1955/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1956void xfrm_state_delete_tunnel(struct xfrm_state *x)
1957{
1958 if (x->tunnel) {
1959 struct xfrm_state *t = x->tunnel;
1960
1961 if (atomic_read(&t->tunnel_users) == 2)
1962 xfrm_state_delete(t);
1963 atomic_dec(&t->tunnel_users);
1964 xfrm_state_put(t);
1965 x->tunnel = NULL;
1966 }
1967}
1968EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1969
1970int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1971{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001972 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
Patrick McHardyc5c25232007-04-09 11:47:18 -07001974 spin_lock_bh(&x->lock);
1975 if (x->km.state == XFRM_STATE_VALID &&
1976 x->type && x->type->get_mtu)
1977 res = x->type->get_mtu(x, mtu);
1978 else
Patrick McHardy28121612007-06-18 22:30:15 -07001979 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001980 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 return res;
1982}
1983
Herbert Xu72cb6962005-06-20 13:18:08 -07001984int xfrm_init_state(struct xfrm_state *x)
1985{
Herbert Xud094cd82005-06-20 13:19:41 -07001986 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001987 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001988 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001989 int err;
1990
Herbert Xud094cd82005-06-20 13:19:41 -07001991 err = -EAFNOSUPPORT;
1992 afinfo = xfrm_state_get_afinfo(family);
1993 if (!afinfo)
1994 goto error;
1995
1996 err = 0;
1997 if (afinfo->init_flags)
1998 err = afinfo->init_flags(x);
1999
2000 xfrm_state_put_afinfo(afinfo);
2001
2002 if (err)
2003 goto error;
2004
2005 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002006
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002007 if (x->sel.family != AF_UNSPEC) {
2008 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2009 if (inner_mode == NULL)
2010 goto error;
2011
2012 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2013 family != x->sel.family) {
2014 xfrm_put_mode(inner_mode);
2015 goto error;
2016 }
2017
2018 x->inner_mode = inner_mode;
2019 } else {
2020 struct xfrm_mode *inner_mode_iaf;
2021
2022 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2023 if (inner_mode == NULL)
2024 goto error;
2025
2026 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2027 xfrm_put_mode(inner_mode);
2028 goto error;
2029 }
2030
2031 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2032 if (inner_mode_iaf == NULL)
2033 goto error;
2034
2035 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2036 xfrm_put_mode(inner_mode_iaf);
2037 goto error;
2038 }
2039
2040 if (x->props.family == AF_INET) {
2041 x->inner_mode = inner_mode;
2042 x->inner_mode_iaf = inner_mode_iaf;
2043 } else {
2044 x->inner_mode = inner_mode_iaf;
2045 x->inner_mode_iaf = inner_mode;
2046 }
2047 }
Herbert Xu13996372007-10-17 21:35:51 -07002048
Herbert Xud094cd82005-06-20 13:19:41 -07002049 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002050 if (x->type == NULL)
2051 goto error;
2052
2053 err = x->type->init_state(x);
2054 if (err)
2055 goto error;
2056
Herbert Xu13996372007-10-17 21:35:51 -07002057 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2058 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002059 goto error;
2060
Herbert Xu72cb6962005-06-20 13:18:08 -07002061 x->km.state = XFRM_STATE_VALID;
2062
2063error:
2064 return err;
2065}
2066
2067EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002068
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002069int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070{
David S. Millerf034b5d2006-08-24 03:08:07 -07002071 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002073 INIT_LIST_HEAD(&net->xfrm.state_all);
2074
David S. Millerf034b5d2006-08-24 03:08:07 -07002075 sz = sizeof(struct hlist_head) * 8;
2076
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002077 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2078 if (!net->xfrm.state_bydst)
2079 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002080 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2081 if (!net->xfrm.state_bysrc)
2082 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002083 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2084 if (!net->xfrm.state_byspi)
2085 goto out_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002086 net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
David S. Millerf034b5d2006-08-24 03:08:07 -07002087
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08002088 net->xfrm.state_num = 0;
Alexey Dobriyan63082732008-11-25 17:19:07 -08002089 INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
Alexey Dobriyanb8a0ae22008-11-25 17:20:11 -08002090 INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
David Howellsc4028952006-11-22 14:57:56 +00002091 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002092 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002093
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002094out_byspi:
2095 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002096out_bysrc:
2097 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002098out_bydst:
2099 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002100}
2101
2102void xfrm_state_fini(struct net *net)
2103{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002104 unsigned int sz;
2105
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002106 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002107
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002108 sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002109 WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2110 xfrm_hash_free(net->xfrm.state_byspi, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002111 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2112 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002113 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2114 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115}
2116
Joy Lattenab5f5e82007-09-17 11:51:22 -07002117#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002118static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2119 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002120{
Paul Moore68277ac2007-12-20 20:49:33 -08002121 struct xfrm_sec_ctx *ctx = x->security;
2122 u32 spi = ntohl(x->id.spi);
2123
2124 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002125 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002126 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002127
2128 switch(x->props.family) {
2129 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002130 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2131 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002132 break;
2133 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002134 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002135 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002136 break;
2137 }
Paul Moore68277ac2007-12-20 20:49:33 -08002138
2139 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002140}
2141
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002142static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2143 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002144{
2145 struct iphdr *iph4;
2146 struct ipv6hdr *iph6;
2147
2148 switch (family) {
2149 case AF_INET:
2150 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002151 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2152 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002153 break;
2154 case AF_INET6:
2155 iph6 = ipv6_hdr(skb);
2156 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002157 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002158 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002159 iph6->flow_lbl[0] & 0x0f,
2160 iph6->flow_lbl[1],
2161 iph6->flow_lbl[2]);
2162 break;
2163 }
2164}
2165
Paul Moore68277ac2007-12-20 20:49:33 -08002166void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002167 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002168{
2169 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002170
Paul Mooreafeb14b2007-12-21 14:58:11 -08002171 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002172 if (audit_buf == NULL)
2173 return;
Eric Paris25323862008-04-18 10:09:25 -04002174 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002175 xfrm_audit_helper_sainfo(x, audit_buf);
2176 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002177 audit_log_end(audit_buf);
2178}
2179EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2180
Paul Moore68277ac2007-12-20 20:49:33 -08002181void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002182 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002183{
2184 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002185
Paul Mooreafeb14b2007-12-21 14:58:11 -08002186 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002187 if (audit_buf == NULL)
2188 return;
Eric Paris25323862008-04-18 10:09:25 -04002189 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002190 xfrm_audit_helper_sainfo(x, audit_buf);
2191 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002192 audit_log_end(audit_buf);
2193}
2194EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002195
2196void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2197 struct sk_buff *skb)
2198{
2199 struct audit_buffer *audit_buf;
2200 u32 spi;
2201
2202 audit_buf = xfrm_audit_start("SA-replay-overflow");
2203 if (audit_buf == NULL)
2204 return;
2205 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2206 /* don't record the sequence number because it's inherent in this kind
2207 * of audit message */
2208 spi = ntohl(x->id.spi);
2209 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2210 audit_log_end(audit_buf);
2211}
2212EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2213
2214static void xfrm_audit_state_replay(struct xfrm_state *x,
2215 struct sk_buff *skb, __be32 net_seq)
2216{
2217 struct audit_buffer *audit_buf;
2218 u32 spi;
2219
2220 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2221 if (audit_buf == NULL)
2222 return;
2223 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2224 spi = ntohl(x->id.spi);
2225 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2226 spi, spi, ntohl(net_seq));
2227 audit_log_end(audit_buf);
2228}
2229
2230void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2231{
2232 struct audit_buffer *audit_buf;
2233
2234 audit_buf = xfrm_audit_start("SA-notfound");
2235 if (audit_buf == NULL)
2236 return;
2237 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2238 audit_log_end(audit_buf);
2239}
2240EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2241
2242void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2243 __be32 net_spi, __be32 net_seq)
2244{
2245 struct audit_buffer *audit_buf;
2246 u32 spi;
2247
2248 audit_buf = xfrm_audit_start("SA-notfound");
2249 if (audit_buf == NULL)
2250 return;
2251 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2252 spi = ntohl(net_spi);
2253 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2254 spi, spi, ntohl(net_seq));
2255 audit_log_end(audit_buf);
2256}
2257EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2258
2259void xfrm_audit_state_icvfail(struct xfrm_state *x,
2260 struct sk_buff *skb, u8 proto)
2261{
2262 struct audit_buffer *audit_buf;
2263 __be32 net_spi;
2264 __be32 net_seq;
2265
2266 audit_buf = xfrm_audit_start("SA-icv-failure");
2267 if (audit_buf == NULL)
2268 return;
2269 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2270 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2271 u32 spi = ntohl(net_spi);
2272 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2273 spi, spi, ntohl(net_seq));
2274 }
2275 audit_log_end(audit_buf);
2276}
2277EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002278#endif /* CONFIG_AUDITSYSCALL */