blob: de08ed9a4775eeac66d1f8acc099aa2c5c7ae752 [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;
48static unsigned int xfrm_state_num;
David S. Miller9d4a7062006-08-24 03:18:09 -070049static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Herbert Xu17c2a422007-10-17 21:33:12 -070051static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
52static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
53
Paul Mooreafeb14b2007-12-21 14:58:11 -080054#ifdef CONFIG_AUDITSYSCALL
55static void xfrm_audit_state_replay(struct xfrm_state *x,
56 struct sk_buff *skb, __be32 net_seq);
57#else
58#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
59#endif /* CONFIG_AUDITSYSCALL */
60
David S. Millerc1969f22006-08-24 04:00:03 -070061static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
62 xfrm_address_t *saddr,
63 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070064 unsigned short family)
65{
Alexey Dobriyan529983e2008-11-25 17:18:12 -080066 return __xfrm_dst_hash(daddr, saddr, reqid, family, init_net.xfrm.state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070067}
68
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070069static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
70 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070071 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070072{
Alexey Dobriyan529983e2008-11-25 17:18:12 -080073 return __xfrm_src_hash(daddr, saddr, family, init_net.xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070074}
75
David S. Miller2575b652006-08-24 03:26:44 -070076static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070077xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070078{
Alexey Dobriyan529983e2008-11-25 17:18:12 -080079 return __xfrm_spi_hash(daddr, spi, proto, family, init_net.xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070080}
81
David S. Millerf034b5d2006-08-24 03:08:07 -070082static void xfrm_hash_transfer(struct hlist_head *list,
83 struct hlist_head *ndsttable,
84 struct hlist_head *nsrctable,
85 struct hlist_head *nspitable,
86 unsigned int nhashmask)
87{
88 struct hlist_node *entry, *tmp;
89 struct xfrm_state *x;
90
91 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
92 unsigned int h;
93
David S. Millerc1969f22006-08-24 04:00:03 -070094 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
95 x->props.reqid, x->props.family,
96 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070097 hlist_add_head(&x->bydst, ndsttable+h);
98
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070099 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
100 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700101 nhashmask);
102 hlist_add_head(&x->bysrc, nsrctable+h);
103
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700104 if (x->id.spi) {
105 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
106 x->id.proto, x->props.family,
107 nhashmask);
108 hlist_add_head(&x->byspi, nspitable+h);
109 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700110 }
111}
112
113static unsigned long xfrm_hash_new_size(void)
114{
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800115 return ((init_net.xfrm.state_hmask + 1) << 1) *
David S. Millerf034b5d2006-08-24 03:08:07 -0700116 sizeof(struct hlist_head);
117}
118
119static DEFINE_MUTEX(hash_resize_mutex);
120
David Howellsc4028952006-11-22 14:57:56 +0000121static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700122{
123 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
124 unsigned long nsize, osize;
125 unsigned int nhashmask, ohashmask;
126 int i;
127
128 mutex_lock(&hash_resize_mutex);
129
130 nsize = xfrm_hash_new_size();
David S. Miller44e36b42006-08-24 04:50:50 -0700131 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700132 if (!ndst)
133 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700134 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700135 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700136 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700137 goto out_unlock;
138 }
David S. Miller44e36b42006-08-24 04:50:50 -0700139 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700140 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700141 xfrm_hash_free(ndst, nsize);
142 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700143 goto out_unlock;
144 }
145
146 spin_lock_bh(&xfrm_state_lock);
147
148 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800149 for (i = init_net.xfrm.state_hmask; i >= 0; i--)
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800150 xfrm_hash_transfer(init_net.xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700151 nhashmask);
152
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800153 odst = init_net.xfrm.state_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800154 osrc = init_net.xfrm.state_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800155 ospi = init_net.xfrm.state_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800156 ohashmask = init_net.xfrm.state_hmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700157
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800158 init_net.xfrm.state_bydst = ndst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800159 init_net.xfrm.state_bysrc = nsrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800160 init_net.xfrm.state_byspi = nspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800161 init_net.xfrm.state_hmask = nhashmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700162
163 spin_unlock_bh(&xfrm_state_lock);
164
165 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700166 xfrm_hash_free(odst, osize);
167 xfrm_hash_free(osrc, osize);
168 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700169
170out_unlock:
171 mutex_unlock(&hash_resize_mutex);
172}
173
David Howellsc4028952006-11-22 14:57:56 +0000174static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700175
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176DECLARE_WAIT_QUEUE_HEAD(km_waitq);
177EXPORT_SYMBOL(km_waitq);
178
179static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
180static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
181
182static struct work_struct xfrm_state_gc_work;
Herbert Xu12a169e2008-10-01 07:03:24 -0700183static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184static DEFINE_SPINLOCK(xfrm_state_gc_lock);
185
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800186int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800188int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800189void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700191static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
192{
193 struct xfrm_state_afinfo *afinfo;
194 if (unlikely(family >= NPROTO))
195 return NULL;
196 write_lock_bh(&xfrm_state_afinfo_lock);
197 afinfo = xfrm_state_afinfo[family];
198 if (unlikely(!afinfo))
199 write_unlock_bh(&xfrm_state_afinfo_lock);
200 return afinfo;
201}
202
203static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800204 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700205{
206 write_unlock_bh(&xfrm_state_afinfo_lock);
207}
208
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800209int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700210{
211 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800212 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700213 int err = 0;
214
215 if (unlikely(afinfo == NULL))
216 return -EAFNOSUPPORT;
217 typemap = afinfo->type_map;
218
219 if (likely(typemap[type->proto] == NULL))
220 typemap[type->proto] = type;
221 else
222 err = -EEXIST;
223 xfrm_state_unlock_afinfo(afinfo);
224 return err;
225}
226EXPORT_SYMBOL(xfrm_register_type);
227
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800228int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700229{
230 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800231 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700232 int err = 0;
233
234 if (unlikely(afinfo == NULL))
235 return -EAFNOSUPPORT;
236 typemap = afinfo->type_map;
237
238 if (unlikely(typemap[type->proto] != type))
239 err = -ENOENT;
240 else
241 typemap[type->proto] = NULL;
242 xfrm_state_unlock_afinfo(afinfo);
243 return err;
244}
245EXPORT_SYMBOL(xfrm_unregister_type);
246
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800247static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700248{
249 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800250 const struct xfrm_type **typemap;
251 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700252 int modload_attempted = 0;
253
254retry:
255 afinfo = xfrm_state_get_afinfo(family);
256 if (unlikely(afinfo == NULL))
257 return NULL;
258 typemap = afinfo->type_map;
259
260 type = typemap[proto];
261 if (unlikely(type && !try_module_get(type->owner)))
262 type = NULL;
263 if (!type && !modload_attempted) {
264 xfrm_state_put_afinfo(afinfo);
265 request_module("xfrm-type-%d-%d", family, proto);
266 modload_attempted = 1;
267 goto retry;
268 }
269
270 xfrm_state_put_afinfo(afinfo);
271 return type;
272}
273
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800274static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700275{
276 module_put(type->owner);
277}
278
279int xfrm_register_mode(struct xfrm_mode *mode, int family)
280{
281 struct xfrm_state_afinfo *afinfo;
282 struct xfrm_mode **modemap;
283 int err;
284
285 if (unlikely(mode->encap >= XFRM_MODE_MAX))
286 return -EINVAL;
287
288 afinfo = xfrm_state_lock_afinfo(family);
289 if (unlikely(afinfo == NULL))
290 return -EAFNOSUPPORT;
291
292 err = -EEXIST;
293 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700294 if (modemap[mode->encap])
295 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700296
Herbert Xu17c2a422007-10-17 21:33:12 -0700297 err = -ENOENT;
298 if (!try_module_get(afinfo->owner))
299 goto out;
300
301 mode->afinfo = afinfo;
302 modemap[mode->encap] = mode;
303 err = 0;
304
305out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700306 xfrm_state_unlock_afinfo(afinfo);
307 return err;
308}
309EXPORT_SYMBOL(xfrm_register_mode);
310
311int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
312{
313 struct xfrm_state_afinfo *afinfo;
314 struct xfrm_mode **modemap;
315 int err;
316
317 if (unlikely(mode->encap >= XFRM_MODE_MAX))
318 return -EINVAL;
319
320 afinfo = xfrm_state_lock_afinfo(family);
321 if (unlikely(afinfo == NULL))
322 return -EAFNOSUPPORT;
323
324 err = -ENOENT;
325 modemap = afinfo->mode_map;
326 if (likely(modemap[mode->encap] == mode)) {
327 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700328 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700329 err = 0;
330 }
331
332 xfrm_state_unlock_afinfo(afinfo);
333 return err;
334}
335EXPORT_SYMBOL(xfrm_unregister_mode);
336
337static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
338{
339 struct xfrm_state_afinfo *afinfo;
340 struct xfrm_mode *mode;
341 int modload_attempted = 0;
342
343 if (unlikely(encap >= XFRM_MODE_MAX))
344 return NULL;
345
346retry:
347 afinfo = xfrm_state_get_afinfo(family);
348 if (unlikely(afinfo == NULL))
349 return NULL;
350
351 mode = afinfo->mode_map[encap];
352 if (unlikely(mode && !try_module_get(mode->owner)))
353 mode = NULL;
354 if (!mode && !modload_attempted) {
355 xfrm_state_put_afinfo(afinfo);
356 request_module("xfrm-mode-%d-%d", family, encap);
357 modload_attempted = 1;
358 goto retry;
359 }
360
361 xfrm_state_put_afinfo(afinfo);
362 return mode;
363}
364
365static void xfrm_put_mode(struct xfrm_mode *mode)
366{
367 module_put(mode->owner);
368}
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370static void xfrm_state_gc_destroy(struct xfrm_state *x)
371{
David S. Millera47f0ce2006-08-24 03:54:22 -0700372 del_timer_sync(&x->timer);
373 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800374 kfree(x->aalg);
375 kfree(x->ealg);
376 kfree(x->calg);
377 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700378 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700379 if (x->inner_mode)
380 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700381 if (x->inner_mode_iaf)
382 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700383 if (x->outer_mode)
384 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 if (x->type) {
386 x->type->destructor(x);
387 xfrm_put_type(x->type);
388 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800389 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 kfree(x);
391}
392
David Howellsc4028952006-11-22 14:57:56 +0000393static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Herbert Xu12a169e2008-10-01 07:03:24 -0700395 struct xfrm_state *x;
396 struct hlist_node *entry, *tmp;
397 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700400 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 spin_unlock_bh(&xfrm_state_gc_lock);
402
Herbert Xu12a169e2008-10-01 07:03:24 -0700403 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 wake_up(&km_waitq);
407}
408
409static inline unsigned long make_jiffies(long secs)
410{
411 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
412 return MAX_SCHEDULE_TIMEOUT-1;
413 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900414 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
417static void xfrm_timer_handler(unsigned long data)
418{
419 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800420 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 long next = LONG_MAX;
422 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600423 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 spin_lock(&x->lock);
426 if (x->km.state == XFRM_STATE_DEAD)
427 goto out;
428 if (x->km.state == XFRM_STATE_EXPIRED)
429 goto expired;
430 if (x->lft.hard_add_expires_seconds) {
431 long tmo = x->lft.hard_add_expires_seconds +
432 x->curlft.add_time - now;
433 if (tmo <= 0)
434 goto expired;
435 if (tmo < next)
436 next = tmo;
437 }
438 if (x->lft.hard_use_expires_seconds) {
439 long tmo = x->lft.hard_use_expires_seconds +
440 (x->curlft.use_time ? : now) - now;
441 if (tmo <= 0)
442 goto expired;
443 if (tmo < next)
444 next = tmo;
445 }
446 if (x->km.dying)
447 goto resched;
448 if (x->lft.soft_add_expires_seconds) {
449 long tmo = x->lft.soft_add_expires_seconds +
450 x->curlft.add_time - now;
451 if (tmo <= 0)
452 warn = 1;
453 else if (tmo < next)
454 next = tmo;
455 }
456 if (x->lft.soft_use_expires_seconds) {
457 long tmo = x->lft.soft_use_expires_seconds +
458 (x->curlft.use_time ? : now) - now;
459 if (tmo <= 0)
460 warn = 1;
461 else if (tmo < next)
462 next = tmo;
463 }
464
Herbert Xu4666faa2005-06-18 22:43:22 -0700465 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800467 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700469 if (next != LONG_MAX)
470 mod_timer(&x->timer, jiffies + make_jiffies(next));
471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 goto out;
473
474expired:
475 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
476 x->km.state = XFRM_STATE_EXPIRED;
477 wake_up(&km_waitq);
478 next = 2;
479 goto resched;
480 }
Joy Latten161a09e2006-11-27 13:11:54 -0600481
482 err = __xfrm_state_delete(x);
483 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800484 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
Joy Lattenab5f5e82007-09-17 11:51:22 -0700486 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400487 audit_get_loginuid(current),
488 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490out:
491 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
David S. Miller0ac84752006-03-20 19:18:23 -0800494static void xfrm_replay_timer_handler(unsigned long data);
495
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800496struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
498 struct xfrm_state *x;
499
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700500 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800503 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 atomic_set(&x->refcnt, 1);
505 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700506 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700507 INIT_HLIST_NODE(&x->bydst);
508 INIT_HLIST_NODE(&x->bysrc);
509 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800510 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
511 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
512 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800513 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 x->lft.soft_byte_limit = XFRM_INF;
515 x->lft.soft_packet_limit = XFRM_INF;
516 x->lft.hard_byte_limit = XFRM_INF;
517 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800518 x->replay_maxage = 0;
519 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700520 x->inner_mode = NULL;
521 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 spin_lock_init(&x->lock);
523 }
524 return x;
525}
526EXPORT_SYMBOL(xfrm_state_alloc);
527
528void __xfrm_state_destroy(struct xfrm_state *x)
529{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700530 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700533 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 spin_unlock_bh(&xfrm_state_gc_lock);
535 schedule_work(&xfrm_state_gc_work);
536}
537EXPORT_SYMBOL(__xfrm_state_destroy);
538
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800539int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700541 int err = -ESRCH;
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (x->km.state != XFRM_STATE_DEAD) {
544 x->km.state = XFRM_STATE_DEAD;
545 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700546 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700547 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700548 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700549 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700550 hlist_del(&x->byspi);
David S. Millerf034b5d2006-08-24 03:08:07 -0700551 xfrm_state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 /* All xfrm_state objects are created by xfrm_state_alloc.
555 * The xfrm_state_alloc call gives a reference, and that
556 * is what we are dropping here.
557 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800558 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700559 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700561
562 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800564EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700566int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700568 int err;
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700571 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700573
574 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576EXPORT_SYMBOL(xfrm_state_delete);
577
Joy Latten4aa2e622007-06-04 19:05:57 -0400578#ifdef CONFIG_SECURITY_NETWORK_XFRM
579static inline int
580xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
Joy Latten4aa2e622007-06-04 19:05:57 -0400582 int i, err = 0;
583
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800584 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400585 struct hlist_node *entry;
586 struct xfrm_state *x;
587
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800588 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400589 if (xfrm_id_proto_match(x->id.proto, proto) &&
590 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700591 xfrm_audit_state_delete(x, 0,
592 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400593 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700594 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400595 return err;
596 }
597 }
598 }
599
600 return err;
601}
602#else
603static inline int
604xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
605{
606 return 0;
607}
608#endif
609
610int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
611{
612 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400615 err = xfrm_state_flush_secctx_check(proto, audit_info);
616 if (err)
617 goto out;
618
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800619 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700620 struct hlist_node *entry;
621 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800623 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700625 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 xfrm_state_hold(x);
627 spin_unlock_bh(&xfrm_state_lock);
628
Joy Latten161a09e2006-11-27 13:11:54 -0600629 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700630 xfrm_audit_state_delete(x, err ? 0 : 1,
631 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400632 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700633 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 xfrm_state_put(x);
635
636 spin_lock_bh(&xfrm_state_lock);
637 goto restart;
638 }
639 }
640 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400641 err = 0;
642
643out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 spin_unlock_bh(&xfrm_state_lock);
645 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400646 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648EXPORT_SYMBOL(xfrm_state_flush);
649
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700650void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700651{
652 spin_lock_bh(&xfrm_state_lock);
653 si->sadcnt = xfrm_state_num;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800654 si->sadhcnt = init_net.xfrm.state_hmask;
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700655 si->sadhmcnt = xfrm_state_hashmax;
656 spin_unlock_bh(&xfrm_state_lock);
657}
658EXPORT_SYMBOL(xfrm_sad_getinfo);
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660static int
661xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
662 struct xfrm_tmpl *tmpl,
663 xfrm_address_t *daddr, xfrm_address_t *saddr,
664 unsigned short family)
665{
666 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
667 if (!afinfo)
668 return -1;
669 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
670 xfrm_state_put_afinfo(afinfo);
671 return 0;
672}
673
Al Viroa94cfd12006-09-27 18:47:24 -0700674static 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 -0700675{
676 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
677 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700678 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700679
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800680 hlist_for_each_entry(x, entry, init_net.xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700681 if (x->props.family != family ||
682 x->id.spi != spi ||
683 x->id.proto != proto)
684 continue;
685
686 switch (family) {
687 case AF_INET:
688 if (x->id.daddr.a4 != daddr->a4)
689 continue;
690 break;
691 case AF_INET6:
692 if (!ipv6_addr_equal((struct in6_addr *)daddr,
693 (struct in6_addr *)
694 x->id.daddr.a6))
695 continue;
696 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700697 }
David S. Milleredcd5822006-08-24 00:42:45 -0700698
699 xfrm_state_hold(x);
700 return x;
701 }
702
703 return NULL;
704}
705
706static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
707{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700708 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700709 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700710 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700711
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800712 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700713 if (x->props.family != family ||
714 x->id.proto != proto)
715 continue;
716
717 switch (family) {
718 case AF_INET:
719 if (x->id.daddr.a4 != daddr->a4 ||
720 x->props.saddr.a4 != saddr->a4)
721 continue;
722 break;
723 case AF_INET6:
724 if (!ipv6_addr_equal((struct in6_addr *)daddr,
725 (struct in6_addr *)
726 x->id.daddr.a6) ||
727 !ipv6_addr_equal((struct in6_addr *)saddr,
728 (struct in6_addr *)
729 x->props.saddr.a6))
730 continue;
731 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700732 }
David S. Milleredcd5822006-08-24 00:42:45 -0700733
734 xfrm_state_hold(x);
735 return x;
736 }
737
738 return NULL;
739}
740
741static inline struct xfrm_state *
742__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
743{
744 if (use_spi)
745 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
746 x->id.proto, family);
747 else
748 return __xfrm_state_lookup_byaddr(&x->id.daddr,
749 &x->props.saddr,
750 x->id.proto, family);
751}
752
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700753static void xfrm_hash_grow_check(int have_hash_collision)
754{
755 if (have_hash_collision &&
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800756 (init_net.xfrm.state_hmask + 1) < xfrm_state_hashmax &&
757 xfrm_state_num > init_net.xfrm.state_hmask)
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700758 schedule_work(&xfrm_hash_work);
759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900762xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 struct flowi *fl, struct xfrm_tmpl *tmpl,
764 struct xfrm_policy *pol, int *err,
765 unsigned short family)
766{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800767 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700768 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700769 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 int acquire_in_progress = 0;
771 int error = 0;
772 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900773
David S. Miller37b08e32008-09-02 20:14:15 -0700774 to_put = NULL;
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800777 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800778 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (x->props.family == family &&
780 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700781 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 xfrm_state_addr_check(x, daddr, saddr, family) &&
783 tmpl->mode == x->props.mode &&
784 tmpl->id.proto == x->id.proto &&
785 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
786 /* Resolution logic:
787 1. There is a valid state with matching selector.
788 Done.
789 2. Valid state with inappropriate selector. Skip.
790
791 Entering area of "sysdeps".
792
793 3. If state is not valid, selector is temporary,
794 it selects only session which triggered
795 previous resolution. Key manager will do
796 something to install a state with proper
797 selector.
798 */
799 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700800 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700801 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 continue;
803 if (!best ||
804 best->km.dying > x->km.dying ||
805 (best->km.dying == x->km.dying &&
806 best->curlft.add_time < x->curlft.add_time))
807 best = x;
808 } else if (x->km.state == XFRM_STATE_ACQ) {
809 acquire_in_progress = 1;
810 } else if (x->km.state == XFRM_STATE_ERROR ||
811 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700812 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700813 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 error = -ESRCH;
815 }
816 }
817 }
818
819 x = best;
820 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700821 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700822 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
823 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700824 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 error = -EEXIST;
826 goto out;
827 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800828 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (x == NULL) {
830 error = -ENOMEM;
831 goto out;
832 }
833 /* Initialize temporary selector matching only
834 * to current session. */
835 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
836
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700837 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
838 if (error) {
839 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700840 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700841 x = NULL;
842 goto out;
843 }
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (km_query(x, tmpl, pol) == 0) {
846 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800847 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800848 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700849 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800850 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (x->id.spi) {
852 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800853 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
David S. Miller01e67d02007-05-25 00:41:38 -0700855 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
856 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 add_timer(&x->timer);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700858 xfrm_state_num++;
859 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 } else {
861 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700862 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 x = NULL;
864 error = -ESRCH;
865 }
866 }
867out:
868 if (x)
869 xfrm_state_hold(x);
870 else
871 *err = acquire_in_progress ? -EAGAIN : error;
872 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700873 if (to_put)
874 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return x;
876}
877
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700878struct xfrm_state *
879xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
880 unsigned short family, u8 mode, u8 proto, u32 reqid)
881{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800882 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700883 struct xfrm_state *rx = NULL, *x = NULL;
884 struct hlist_node *entry;
885
886 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800887 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800888 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700889 if (x->props.family == family &&
890 x->props.reqid == reqid &&
891 !(x->props.flags & XFRM_STATE_WILDRECV) &&
892 xfrm_state_addr_check(x, daddr, saddr, family) &&
893 mode == x->props.mode &&
894 proto == x->id.proto &&
895 x->km.state == XFRM_STATE_VALID) {
896 rx = x;
897 break;
898 }
899 }
900
901 if (rx)
902 xfrm_state_hold(rx);
903 spin_unlock(&xfrm_state_lock);
904
905
906 return rx;
907}
908EXPORT_SYMBOL(xfrm_stateonly_find);
909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910static void __xfrm_state_insert(struct xfrm_state *x)
911{
David S. Millera624c102006-08-24 03:24:33 -0700912 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
David S. Miller9d4a7062006-08-24 03:18:09 -0700914 x->genid = ++xfrm_state_genid;
915
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800916 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800917
David S. Millerc1969f22006-08-24 04:00:03 -0700918 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
919 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800920 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700922 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800923 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700925 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700926 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
927 x->props.family);
928
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800929 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700930 }
931
David S. Millera47f0ce2006-08-24 03:54:22 -0700932 mod_timer(&x->timer, jiffies + HZ);
933 if (x->replay_maxage)
934 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700937
938 xfrm_state_num++;
939
David S. Miller918049f2006-10-12 22:03:24 -0700940 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
David S. Millerc7f5ea32006-08-24 03:29:04 -0700943/* xfrm_state_lock is held */
944static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
945{
946 unsigned short family = xnew->props.family;
947 u32 reqid = xnew->props.reqid;
948 struct xfrm_state *x;
949 struct hlist_node *entry;
950 unsigned int h;
951
David S. Millerc1969f22006-08-24 04:00:03 -0700952 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800953 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700954 if (x->props.family == family &&
955 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700956 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
957 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700958 x->genid = xfrm_state_genid;
959 }
960}
961
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962void xfrm_state_insert(struct xfrm_state *x)
963{
964 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700965 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 __xfrm_state_insert(x);
967 spin_unlock_bh(&xfrm_state_lock);
968}
969EXPORT_SYMBOL(xfrm_state_insert);
970
David S. Miller27708342006-08-24 00:13:10 -0700971/* xfrm_state_lock is held */
972static 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)
973{
David S. Millerc1969f22006-08-24 04:00:03 -0700974 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700975 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700976 struct xfrm_state *x;
977
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800978 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700979 if (x->props.reqid != reqid ||
980 x->props.mode != mode ||
981 x->props.family != family ||
982 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700983 x->id.spi != 0 ||
984 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700985 continue;
986
987 switch (family) {
988 case AF_INET:
989 if (x->id.daddr.a4 != daddr->a4 ||
990 x->props.saddr.a4 != saddr->a4)
991 continue;
992 break;
993 case AF_INET6:
994 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
995 (struct in6_addr *)daddr) ||
996 !ipv6_addr_equal((struct in6_addr *)
997 x->props.saddr.a6,
998 (struct in6_addr *)saddr))
999 continue;
1000 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001001 }
David S. Miller27708342006-08-24 00:13:10 -07001002
1003 xfrm_state_hold(x);
1004 return x;
1005 }
1006
1007 if (!create)
1008 return NULL;
1009
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001010 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001011 if (likely(x)) {
1012 switch (family) {
1013 case AF_INET:
1014 x->sel.daddr.a4 = daddr->a4;
1015 x->sel.saddr.a4 = saddr->a4;
1016 x->sel.prefixlen_d = 32;
1017 x->sel.prefixlen_s = 32;
1018 x->props.saddr.a4 = saddr->a4;
1019 x->id.daddr.a4 = daddr->a4;
1020 break;
1021
1022 case AF_INET6:
1023 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1024 (struct in6_addr *)daddr);
1025 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1026 (struct in6_addr *)saddr);
1027 x->sel.prefixlen_d = 128;
1028 x->sel.prefixlen_s = 128;
1029 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1030 (struct in6_addr *)saddr);
1031 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1032 (struct in6_addr *)daddr);
1033 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001034 }
David S. Miller27708342006-08-24 00:13:10 -07001035
1036 x->km.state = XFRM_STATE_ACQ;
1037 x->id.proto = proto;
1038 x->props.family = family;
1039 x->props.mode = mode;
1040 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001041 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001042 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001043 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001044 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001045 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001046 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001047 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001048 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001049
1050 xfrm_state_num++;
1051
1052 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001053 }
1054
1055 return x;
1056}
1057
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1059
1060int xfrm_state_add(struct xfrm_state *x)
1061{
David S. Miller37b08e32008-09-02 20:14:15 -07001062 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 int family;
1064 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001065 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
David S. Miller37b08e32008-09-02 20:14:15 -07001069 to_put = NULL;
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 spin_lock_bh(&xfrm_state_lock);
1072
David S. Milleredcd5822006-08-24 00:42:45 -07001073 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001075 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 x1 = NULL;
1077 err = -EEXIST;
1078 goto out;
1079 }
1080
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001081 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001083 if (x1 && ((x1->id.proto != x->id.proto) ||
1084 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001085 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 x1 = NULL;
1087 }
1088 }
1089
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001090 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001091 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1092 x->id.proto,
1093 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
David S. Millerc7f5ea32006-08-24 03:29:04 -07001095 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 __xfrm_state_insert(x);
1097 err = 0;
1098
1099out:
1100 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
1102 if (x1) {
1103 xfrm_state_delete(x1);
1104 xfrm_state_put(x1);
1105 }
1106
David S. Miller37b08e32008-09-02 20:14:15 -07001107 if (to_put)
1108 xfrm_state_put(to_put);
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return err;
1111}
1112EXPORT_SYMBOL(xfrm_state_add);
1113
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001114#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001115static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001116{
1117 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001118 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001119 if (!x)
1120 goto error;
1121
1122 memcpy(&x->id, &orig->id, sizeof(x->id));
1123 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1124 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1125 x->props.mode = orig->props.mode;
1126 x->props.replay_window = orig->props.replay_window;
1127 x->props.reqid = orig->props.reqid;
1128 x->props.family = orig->props.family;
1129 x->props.saddr = orig->props.saddr;
1130
1131 if (orig->aalg) {
1132 x->aalg = xfrm_algo_clone(orig->aalg);
1133 if (!x->aalg)
1134 goto error;
1135 }
1136 x->props.aalgo = orig->props.aalgo;
1137
1138 if (orig->ealg) {
1139 x->ealg = xfrm_algo_clone(orig->ealg);
1140 if (!x->ealg)
1141 goto error;
1142 }
1143 x->props.ealgo = orig->props.ealgo;
1144
1145 if (orig->calg) {
1146 x->calg = xfrm_algo_clone(orig->calg);
1147 if (!x->calg)
1148 goto error;
1149 }
1150 x->props.calgo = orig->props.calgo;
1151
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001152 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001153 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1154 if (!x->encap)
1155 goto error;
1156 }
1157
1158 if (orig->coaddr) {
1159 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1160 GFP_KERNEL);
1161 if (!x->coaddr)
1162 goto error;
1163 }
1164
1165 err = xfrm_init_state(x);
1166 if (err)
1167 goto error;
1168
1169 x->props.flags = orig->props.flags;
1170
1171 x->curlft.add_time = orig->curlft.add_time;
1172 x->km.state = orig->km.state;
1173 x->km.seq = orig->km.seq;
1174
1175 return x;
1176
1177 error:
1178 if (errp)
1179 *errp = err;
1180 if (x) {
1181 kfree(x->aalg);
1182 kfree(x->ealg);
1183 kfree(x->calg);
1184 kfree(x->encap);
1185 kfree(x->coaddr);
1186 }
1187 kfree(x);
1188 return NULL;
1189}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001190
1191/* xfrm_state_lock is held */
1192struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1193{
1194 unsigned int h;
1195 struct xfrm_state *x;
1196 struct hlist_node *entry;
1197
1198 if (m->reqid) {
1199 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1200 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001201 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001202 if (x->props.mode != m->mode ||
1203 x->id.proto != m->proto)
1204 continue;
1205 if (m->reqid && x->props.reqid != m->reqid)
1206 continue;
1207 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1208 m->old_family) ||
1209 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1210 m->old_family))
1211 continue;
1212 xfrm_state_hold(x);
1213 return x;
1214 }
1215 } else {
1216 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1217 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001218 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001219 if (x->props.mode != m->mode ||
1220 x->id.proto != m->proto)
1221 continue;
1222 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1223 m->old_family) ||
1224 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1225 m->old_family))
1226 continue;
1227 xfrm_state_hold(x);
1228 return x;
1229 }
1230 }
1231
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001232 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001233}
1234EXPORT_SYMBOL(xfrm_migrate_state_find);
1235
1236struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1237 struct xfrm_migrate *m)
1238{
1239 struct xfrm_state *xc;
1240 int err;
1241
1242 xc = xfrm_state_clone(x, &err);
1243 if (!xc)
1244 return NULL;
1245
1246 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1247 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1248
1249 /* add state */
1250 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1251 /* a care is needed when the destination address of the
1252 state is to be updated as it is a part of triplet */
1253 xfrm_state_insert(xc);
1254 } else {
1255 if ((err = xfrm_state_add(xc)) < 0)
1256 goto error;
1257 }
1258
1259 return xc;
1260error:
1261 kfree(xc);
1262 return NULL;
1263}
1264EXPORT_SYMBOL(xfrm_state_migrate);
1265#endif
1266
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267int xfrm_state_update(struct xfrm_state *x)
1268{
David S. Miller37b08e32008-09-02 20:14:15 -07001269 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001271 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
David S. Miller37b08e32008-09-02 20:14:15 -07001273 to_put = NULL;
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001276 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278 err = -ESRCH;
1279 if (!x1)
1280 goto out;
1281
1282 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001283 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 err = -EEXIST;
1285 goto out;
1286 }
1287
1288 if (x1->km.state == XFRM_STATE_ACQ) {
1289 __xfrm_state_insert(x);
1290 x = NULL;
1291 }
1292 err = 0;
1293
1294out:
1295 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
David S. Miller37b08e32008-09-02 20:14:15 -07001297 if (to_put)
1298 xfrm_state_put(to_put);
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (err)
1301 return err;
1302
1303 if (!x) {
1304 xfrm_state_delete(x1);
1305 xfrm_state_put(x1);
1306 return 0;
1307 }
1308
1309 err = -EINVAL;
1310 spin_lock_bh(&x1->lock);
1311 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1312 if (x->encap && x1->encap)
1313 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001314 if (x->coaddr && x1->coaddr) {
1315 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1316 }
1317 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1318 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1320 x1->km.dying = 0;
1321
David S. Millera47f0ce2006-08-24 03:54:22 -07001322 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (x1->curlft.use_time)
1324 xfrm_state_check_expire(x1);
1325
1326 err = 0;
1327 }
1328 spin_unlock_bh(&x1->lock);
1329
1330 xfrm_state_put(x1);
1331
1332 return err;
1333}
1334EXPORT_SYMBOL(xfrm_state_update);
1335
1336int xfrm_state_check_expire(struct xfrm_state *x)
1337{
1338 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001339 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
1341 if (x->km.state != XFRM_STATE_VALID)
1342 return -EINVAL;
1343
1344 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1345 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001346 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001347 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 return -EINVAL;
1349 }
1350
1351 if (!x->km.dying &&
1352 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001353 x->curlft.packets >= x->lft.soft_packet_limit)) {
1354 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001355 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 return 0;
1358}
1359EXPORT_SYMBOL(xfrm_state_check_expire);
1360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001362xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 unsigned short family)
1364{
1365 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001368 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 return x;
1371}
1372EXPORT_SYMBOL(xfrm_state_lookup);
1373
1374struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001375xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1376 u8 proto, unsigned short family)
1377{
1378 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001379
1380 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001381 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001382 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001383 return x;
1384}
1385EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1386
1387struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001388xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1389 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 int create, unsigned short family)
1391{
1392 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001395 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 return x;
1399}
1400EXPORT_SYMBOL(xfrm_find_acq);
1401
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001402#ifdef CONFIG_XFRM_SUB_POLICY
1403int
1404xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1405 unsigned short family)
1406{
1407 int err = 0;
1408 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1409 if (!afinfo)
1410 return -EAFNOSUPPORT;
1411
1412 spin_lock_bh(&xfrm_state_lock);
1413 if (afinfo->tmpl_sort)
1414 err = afinfo->tmpl_sort(dst, src, n);
1415 spin_unlock_bh(&xfrm_state_lock);
1416 xfrm_state_put_afinfo(afinfo);
1417 return err;
1418}
1419EXPORT_SYMBOL(xfrm_tmpl_sort);
1420
1421int
1422xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1423 unsigned short family)
1424{
1425 int err = 0;
1426 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1427 if (!afinfo)
1428 return -EAFNOSUPPORT;
1429
1430 spin_lock_bh(&xfrm_state_lock);
1431 if (afinfo->state_sort)
1432 err = afinfo->state_sort(dst, src, n);
1433 spin_unlock_bh(&xfrm_state_lock);
1434 xfrm_state_put_afinfo(afinfo);
1435 return err;
1436}
1437EXPORT_SYMBOL(xfrm_state_sort);
1438#endif
1439
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440/* Silly enough, but I'm lazy to build resolution list */
1441
1442static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1443{
1444 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Alexey Dobriyan529983e2008-11-25 17:18:12 -08001446 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001447 struct hlist_node *entry;
1448 struct xfrm_state *x;
1449
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001450 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001451 if (x->km.seq == seq &&
1452 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 xfrm_state_hold(x);
1454 return x;
1455 }
1456 }
1457 }
1458 return NULL;
1459}
1460
1461struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1462{
1463 struct xfrm_state *x;
1464
1465 spin_lock_bh(&xfrm_state_lock);
1466 x = __xfrm_find_acq_byseq(seq);
1467 spin_unlock_bh(&xfrm_state_lock);
1468 return x;
1469}
1470EXPORT_SYMBOL(xfrm_find_acq_byseq);
1471
1472u32 xfrm_get_acqseq(void)
1473{
1474 u32 res;
1475 static u32 acqseq;
1476 static DEFINE_SPINLOCK(acqseq_lock);
1477
1478 spin_lock_bh(&acqseq_lock);
1479 res = (++acqseq ? : ++acqseq);
1480 spin_unlock_bh(&acqseq_lock);
1481 return res;
1482}
1483EXPORT_SYMBOL(xfrm_get_acqseq);
1484
Herbert Xu658b2192007-10-09 13:29:52 -07001485int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
David S. Millerf034b5d2006-08-24 03:08:07 -07001487 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001489 int err = -ENOENT;
1490 __be32 minspi = htonl(low);
1491 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
Herbert Xu658b2192007-10-09 13:29:52 -07001493 spin_lock_bh(&x->lock);
1494 if (x->km.state == XFRM_STATE_DEAD)
1495 goto unlock;
1496
1497 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001499 goto unlock;
1500
1501 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 if (minspi == maxspi) {
1504 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1505 if (x0) {
1506 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001507 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 }
1509 x->id.spi = minspi;
1510 } else {
1511 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001512 for (h=0; h<high-low+1; h++) {
1513 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1515 if (x0 == NULL) {
1516 x->id.spi = htonl(spi);
1517 break;
1518 }
1519 xfrm_state_put(x0);
1520 }
1521 }
1522 if (x->id.spi) {
1523 spin_lock_bh(&xfrm_state_lock);
1524 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08001525 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001527
1528 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
Herbert Xu658b2192007-10-09 13:29:52 -07001530
1531unlock:
1532 spin_unlock_bh(&x->lock);
1533
1534 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535}
1536EXPORT_SYMBOL(xfrm_alloc_spi);
1537
Timo Teras4c563f72008-02-28 21:31:08 -08001538int xfrm_state_walk(struct xfrm_state_walk *walk,
1539 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 void *data)
1541{
Herbert Xu12a169e2008-10-01 07:03:24 -07001542 struct xfrm_state *state;
1543 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 int err = 0;
1545
Herbert Xu12a169e2008-10-01 07:03:24 -07001546 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001547 return 0;
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001550 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001551 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001552 else
1553 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001554 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001555 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001556 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001557 state = container_of(x, struct xfrm_state, km);
1558 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001559 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001560 err = func(state, walk->seq, data);
1561 if (err) {
1562 list_move_tail(&walk->all, &x->all);
1563 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001565 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001567 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 err = -ENOENT;
1569 goto out;
1570 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001571 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572out:
1573 spin_unlock_bh(&xfrm_state_lock);
1574 return err;
1575}
1576EXPORT_SYMBOL(xfrm_state_walk);
1577
Herbert Xu5c182452008-09-22 19:48:19 -07001578void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1579{
Herbert Xu12a169e2008-10-01 07:03:24 -07001580 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001581 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001582 walk->state = XFRM_STATE_DEAD;
1583 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001584}
1585EXPORT_SYMBOL(xfrm_state_walk_init);
1586
Herbert Xuabb81c42008-09-09 19:58:29 -07001587void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1588{
Herbert Xu12a169e2008-10-01 07:03:24 -07001589 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001590 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001591
Herbert Xu12a169e2008-10-01 07:03:24 -07001592 spin_lock_bh(&xfrm_state_lock);
1593 list_del(&walk->all);
1594 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001595}
1596EXPORT_SYMBOL(xfrm_state_walk_done);
1597
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001598
1599void xfrm_replay_notify(struct xfrm_state *x, int event)
1600{
1601 struct km_event c;
1602 /* we send notify messages in case
1603 * 1. we updated on of the sequence numbers, and the seqno difference
1604 * is at least x->replay_maxdiff, in this case we also update the
1605 * timeout of our timer function
1606 * 2. if x->replay_maxage has elapsed since last update,
1607 * and there were changes
1608 *
1609 * The state structure must be locked!
1610 */
1611
1612 switch (event) {
1613 case XFRM_REPLAY_UPDATE:
1614 if (x->replay_maxdiff &&
1615 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001616 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1617 if (x->xflags & XFRM_TIME_DEFER)
1618 event = XFRM_REPLAY_TIMEOUT;
1619 else
1620 return;
1621 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001622
1623 break;
1624
1625 case XFRM_REPLAY_TIMEOUT:
1626 if ((x->replay.seq == x->preplay.seq) &&
1627 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001628 (x->replay.oseq == x->preplay.oseq)) {
1629 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001630 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001631 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001632
1633 break;
1634 }
1635
1636 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1637 c.event = XFRM_MSG_NEWAE;
1638 c.data.aevent = event;
1639 km_state_notify(x, &c);
1640
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001641 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001642 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001643 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001644}
1645
1646static void xfrm_replay_timer_handler(unsigned long data)
1647{
1648 struct xfrm_state *x = (struct xfrm_state*)data;
1649
1650 spin_lock(&x->lock);
1651
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001652 if (x->km.state == XFRM_STATE_VALID) {
1653 if (xfrm_aevent_is_on())
1654 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1655 else
1656 x->xflags |= XFRM_TIME_DEFER;
1657 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001658
1659 spin_unlock(&x->lock);
1660}
1661
Paul Mooreafeb14b2007-12-21 14:58:11 -08001662int xfrm_replay_check(struct xfrm_state *x,
1663 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664{
1665 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001666 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001669 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 if (likely(seq > x->replay.seq))
1672 return 0;
1673
1674 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001675 if (diff >= min_t(unsigned int, x->props.replay_window,
1676 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001678 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 }
1680
1681 if (x->replay.bitmap & (1U << diff)) {
1682 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001683 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
1685 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001686
1687err:
1688 xfrm_audit_state_replay(x, skb, net_seq);
1689 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Al Viro61f46272006-09-27 18:48:33 -07001692void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001695 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 if (seq > x->replay.seq) {
1698 diff = seq - x->replay.seq;
1699 if (diff < x->props.replay_window)
1700 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1701 else
1702 x->replay.bitmap = 1;
1703 x->replay.seq = seq;
1704 } else {
1705 diff = x->replay.seq - seq;
1706 x->replay.bitmap |= (1U << diff);
1707 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001708
1709 if (xfrm_aevent_is_on())
1710 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
Denis Chengdf018122007-12-07 00:51:11 -08001713static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714static DEFINE_RWLOCK(xfrm_km_lock);
1715
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001716void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
1718 struct xfrm_mgr *km;
1719
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001720 read_lock(&xfrm_km_lock);
1721 list_for_each_entry(km, &xfrm_km_list, list)
1722 if (km->notify_policy)
1723 km->notify_policy(xp, dir, c);
1724 read_unlock(&xfrm_km_lock);
1725}
1726
1727void km_state_notify(struct xfrm_state *x, struct km_event *c)
1728{
1729 struct xfrm_mgr *km;
1730 read_lock(&xfrm_km_lock);
1731 list_for_each_entry(km, &xfrm_km_list, list)
1732 if (km->notify)
1733 km->notify(x, c);
1734 read_unlock(&xfrm_km_lock);
1735}
1736
1737EXPORT_SYMBOL(km_policy_notify);
1738EXPORT_SYMBOL(km_state_notify);
1739
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001740void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001741{
1742 struct km_event c;
1743
Herbert Xubf088672005-06-18 22:44:00 -07001744 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001745 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001746 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001747 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749 if (hard)
1750 wake_up(&km_waitq);
1751}
1752
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001753EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001754/*
1755 * We send to all registered managers regardless of failure
1756 * We are happy with one success
1757*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001758int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001760 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 struct xfrm_mgr *km;
1762
1763 read_lock(&xfrm_km_lock);
1764 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001765 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1766 if (!acqret)
1767 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 }
1769 read_unlock(&xfrm_km_lock);
1770 return err;
1771}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001772EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Al Viro5d36b182006-11-08 00:24:06 -08001774int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775{
1776 int err = -EINVAL;
1777 struct xfrm_mgr *km;
1778
1779 read_lock(&xfrm_km_lock);
1780 list_for_each_entry(km, &xfrm_km_list, list) {
1781 if (km->new_mapping)
1782 err = km->new_mapping(x, ipaddr, sport);
1783 if (!err)
1784 break;
1785 }
1786 read_unlock(&xfrm_km_lock);
1787 return err;
1788}
1789EXPORT_SYMBOL(km_new_mapping);
1790
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001791void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001793 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
Herbert Xubf088672005-06-18 22:44:00 -07001795 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001796 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001797 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001798 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
1800 if (hard)
1801 wake_up(&km_waitq);
1802}
David S. Millera70fcb02006-03-20 19:18:52 -08001803EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001805#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001806int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001807 struct xfrm_migrate *m, int num_migrate,
1808 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001809{
1810 int err = -EINVAL;
1811 int ret;
1812 struct xfrm_mgr *km;
1813
1814 read_lock(&xfrm_km_lock);
1815 list_for_each_entry(km, &xfrm_km_list, list) {
1816 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001817 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001818 if (!ret)
1819 err = ret;
1820 }
1821 }
1822 read_unlock(&xfrm_km_lock);
1823 return err;
1824}
1825EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001826#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001827
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001828int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1829{
1830 int err = -EINVAL;
1831 int ret;
1832 struct xfrm_mgr *km;
1833
1834 read_lock(&xfrm_km_lock);
1835 list_for_each_entry(km, &xfrm_km_list, list) {
1836 if (km->report) {
1837 ret = km->report(proto, sel, addr);
1838 if (!ret)
1839 err = ret;
1840 }
1841 }
1842 read_unlock(&xfrm_km_lock);
1843 return err;
1844}
1845EXPORT_SYMBOL(km_report);
1846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1848{
1849 int err;
1850 u8 *data;
1851 struct xfrm_mgr *km;
1852 struct xfrm_policy *pol = NULL;
1853
1854 if (optlen <= 0 || optlen > PAGE_SIZE)
1855 return -EMSGSIZE;
1856
1857 data = kmalloc(optlen, GFP_KERNEL);
1858 if (!data)
1859 return -ENOMEM;
1860
1861 err = -EFAULT;
1862 if (copy_from_user(data, optval, optlen))
1863 goto out;
1864
1865 err = -EINVAL;
1866 read_lock(&xfrm_km_lock);
1867 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001868 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 optlen, &err);
1870 if (err >= 0)
1871 break;
1872 }
1873 read_unlock(&xfrm_km_lock);
1874
1875 if (err >= 0) {
1876 xfrm_sk_policy_insert(sk, err, pol);
1877 xfrm_pol_put(pol);
1878 err = 0;
1879 }
1880
1881out:
1882 kfree(data);
1883 return err;
1884}
1885EXPORT_SYMBOL(xfrm_user_policy);
1886
1887int xfrm_register_km(struct xfrm_mgr *km)
1888{
1889 write_lock_bh(&xfrm_km_lock);
1890 list_add_tail(&km->list, &xfrm_km_list);
1891 write_unlock_bh(&xfrm_km_lock);
1892 return 0;
1893}
1894EXPORT_SYMBOL(xfrm_register_km);
1895
1896int xfrm_unregister_km(struct xfrm_mgr *km)
1897{
1898 write_lock_bh(&xfrm_km_lock);
1899 list_del(&km->list);
1900 write_unlock_bh(&xfrm_km_lock);
1901 return 0;
1902}
1903EXPORT_SYMBOL(xfrm_unregister_km);
1904
1905int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1906{
1907 int err = 0;
1908 if (unlikely(afinfo == NULL))
1909 return -EINVAL;
1910 if (unlikely(afinfo->family >= NPROTO))
1911 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001912 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1914 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001915 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001917 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 return err;
1919}
1920EXPORT_SYMBOL(xfrm_state_register_afinfo);
1921
1922int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1923{
1924 int err = 0;
1925 if (unlikely(afinfo == NULL))
1926 return -EINVAL;
1927 if (unlikely(afinfo->family >= NPROTO))
1928 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001929 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1931 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1932 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001933 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001936 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 return err;
1938}
1939EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1940
Herbert Xu17c2a422007-10-17 21:33:12 -07001941static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942{
1943 struct xfrm_state_afinfo *afinfo;
1944 if (unlikely(family >= NPROTO))
1945 return NULL;
1946 read_lock(&xfrm_state_afinfo_lock);
1947 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001948 if (unlikely(!afinfo))
1949 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 return afinfo;
1951}
1952
Herbert Xu17c2a422007-10-17 21:33:12 -07001953static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001954 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
Herbert Xu546be242006-05-27 23:03:58 -07001956 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
1959/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1960void xfrm_state_delete_tunnel(struct xfrm_state *x)
1961{
1962 if (x->tunnel) {
1963 struct xfrm_state *t = x->tunnel;
1964
1965 if (atomic_read(&t->tunnel_users) == 2)
1966 xfrm_state_delete(t);
1967 atomic_dec(&t->tunnel_users);
1968 xfrm_state_put(t);
1969 x->tunnel = NULL;
1970 }
1971}
1972EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1973
1974int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1975{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001976 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Patrick McHardyc5c25232007-04-09 11:47:18 -07001978 spin_lock_bh(&x->lock);
1979 if (x->km.state == XFRM_STATE_VALID &&
1980 x->type && x->type->get_mtu)
1981 res = x->type->get_mtu(x, mtu);
1982 else
Patrick McHardy28121612007-06-18 22:30:15 -07001983 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001984 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 return res;
1986}
1987
Herbert Xu72cb6962005-06-20 13:18:08 -07001988int xfrm_init_state(struct xfrm_state *x)
1989{
Herbert Xud094cd82005-06-20 13:19:41 -07001990 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001991 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001992 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001993 int err;
1994
Herbert Xud094cd82005-06-20 13:19:41 -07001995 err = -EAFNOSUPPORT;
1996 afinfo = xfrm_state_get_afinfo(family);
1997 if (!afinfo)
1998 goto error;
1999
2000 err = 0;
2001 if (afinfo->init_flags)
2002 err = afinfo->init_flags(x);
2003
2004 xfrm_state_put_afinfo(afinfo);
2005
2006 if (err)
2007 goto error;
2008
2009 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002010
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002011 if (x->sel.family != AF_UNSPEC) {
2012 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2013 if (inner_mode == NULL)
2014 goto error;
2015
2016 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2017 family != x->sel.family) {
2018 xfrm_put_mode(inner_mode);
2019 goto error;
2020 }
2021
2022 x->inner_mode = inner_mode;
2023 } else {
2024 struct xfrm_mode *inner_mode_iaf;
2025
2026 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2027 if (inner_mode == NULL)
2028 goto error;
2029
2030 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2031 xfrm_put_mode(inner_mode);
2032 goto error;
2033 }
2034
2035 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2036 if (inner_mode_iaf == NULL)
2037 goto error;
2038
2039 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2040 xfrm_put_mode(inner_mode_iaf);
2041 goto error;
2042 }
2043
2044 if (x->props.family == AF_INET) {
2045 x->inner_mode = inner_mode;
2046 x->inner_mode_iaf = inner_mode_iaf;
2047 } else {
2048 x->inner_mode = inner_mode_iaf;
2049 x->inner_mode_iaf = inner_mode;
2050 }
2051 }
Herbert Xu13996372007-10-17 21:35:51 -07002052
Herbert Xud094cd82005-06-20 13:19:41 -07002053 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002054 if (x->type == NULL)
2055 goto error;
2056
2057 err = x->type->init_state(x);
2058 if (err)
2059 goto error;
2060
Herbert Xu13996372007-10-17 21:35:51 -07002061 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2062 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002063 goto error;
2064
Herbert Xu72cb6962005-06-20 13:18:08 -07002065 x->km.state = XFRM_STATE_VALID;
2066
2067error:
2068 return err;
2069}
2070
2071EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002072
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002073int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074{
David S. Millerf034b5d2006-08-24 03:08:07 -07002075 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002077 INIT_LIST_HEAD(&net->xfrm.state_all);
2078
David S. Millerf034b5d2006-08-24 03:08:07 -07002079 sz = sizeof(struct hlist_head) * 8;
2080
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002081 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2082 if (!net->xfrm.state_bydst)
2083 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002084 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2085 if (!net->xfrm.state_bysrc)
2086 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002087 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2088 if (!net->xfrm.state_byspi)
2089 goto out_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002090 net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
David S. Millerf034b5d2006-08-24 03:08:07 -07002091
David Howellsc4028952006-11-22 14:57:56 +00002092 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002093 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002094
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002095out_byspi:
2096 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002097out_bysrc:
2098 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002099out_bydst:
2100 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002101}
2102
2103void xfrm_state_fini(struct net *net)
2104{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002105 unsigned int sz;
2106
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002107 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002108
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002109 sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002110 WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2111 xfrm_hash_free(net->xfrm.state_byspi, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002112 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2113 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002114 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2115 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116}
2117
Joy Lattenab5f5e82007-09-17 11:51:22 -07002118#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002119static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2120 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002121{
Paul Moore68277ac2007-12-20 20:49:33 -08002122 struct xfrm_sec_ctx *ctx = x->security;
2123 u32 spi = ntohl(x->id.spi);
2124
2125 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002126 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002127 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002128
2129 switch(x->props.family) {
2130 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002131 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2132 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002133 break;
2134 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002135 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002136 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002137 break;
2138 }
Paul Moore68277ac2007-12-20 20:49:33 -08002139
2140 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002141}
2142
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002143static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2144 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002145{
2146 struct iphdr *iph4;
2147 struct ipv6hdr *iph6;
2148
2149 switch (family) {
2150 case AF_INET:
2151 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002152 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2153 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002154 break;
2155 case AF_INET6:
2156 iph6 = ipv6_hdr(skb);
2157 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002158 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002159 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002160 iph6->flow_lbl[0] & 0x0f,
2161 iph6->flow_lbl[1],
2162 iph6->flow_lbl[2]);
2163 break;
2164 }
2165}
2166
Paul Moore68277ac2007-12-20 20:49:33 -08002167void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002168 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002169{
2170 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002171
Paul Mooreafeb14b2007-12-21 14:58:11 -08002172 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002173 if (audit_buf == NULL)
2174 return;
Eric Paris25323862008-04-18 10:09:25 -04002175 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002176 xfrm_audit_helper_sainfo(x, audit_buf);
2177 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002178 audit_log_end(audit_buf);
2179}
2180EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2181
Paul Moore68277ac2007-12-20 20:49:33 -08002182void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002183 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002184{
2185 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002186
Paul Mooreafeb14b2007-12-21 14:58:11 -08002187 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002188 if (audit_buf == NULL)
2189 return;
Eric Paris25323862008-04-18 10:09:25 -04002190 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002191 xfrm_audit_helper_sainfo(x, audit_buf);
2192 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002193 audit_log_end(audit_buf);
2194}
2195EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002196
2197void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2198 struct sk_buff *skb)
2199{
2200 struct audit_buffer *audit_buf;
2201 u32 spi;
2202
2203 audit_buf = xfrm_audit_start("SA-replay-overflow");
2204 if (audit_buf == NULL)
2205 return;
2206 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2207 /* don't record the sequence number because it's inherent in this kind
2208 * of audit message */
2209 spi = ntohl(x->id.spi);
2210 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2211 audit_log_end(audit_buf);
2212}
2213EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2214
2215static void xfrm_audit_state_replay(struct xfrm_state *x,
2216 struct sk_buff *skb, __be32 net_seq)
2217{
2218 struct audit_buffer *audit_buf;
2219 u32 spi;
2220
2221 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2222 if (audit_buf == NULL)
2223 return;
2224 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2225 spi = ntohl(x->id.spi);
2226 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2227 spi, spi, ntohl(net_seq));
2228 audit_log_end(audit_buf);
2229}
2230
2231void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2232{
2233 struct audit_buffer *audit_buf;
2234
2235 audit_buf = xfrm_audit_start("SA-notfound");
2236 if (audit_buf == NULL)
2237 return;
2238 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2239 audit_log_end(audit_buf);
2240}
2241EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2242
2243void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2244 __be32 net_spi, __be32 net_seq)
2245{
2246 struct audit_buffer *audit_buf;
2247 u32 spi;
2248
2249 audit_buf = xfrm_audit_start("SA-notfound");
2250 if (audit_buf == NULL)
2251 return;
2252 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2253 spi = ntohl(net_spi);
2254 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2255 spi, spi, ntohl(net_seq));
2256 audit_log_end(audit_buf);
2257}
2258EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2259
2260void xfrm_audit_state_icvfail(struct xfrm_state *x,
2261 struct sk_buff *skb, u8 proto)
2262{
2263 struct audit_buffer *audit_buf;
2264 __be32 net_spi;
2265 __be32 net_seq;
2266
2267 audit_buf = xfrm_audit_start("SA-icv-failure");
2268 if (audit_buf == NULL)
2269 return;
2270 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2271 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2272 u32 spi = ntohl(net_spi);
2273 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2274 spi, spi, ntohl(net_seq));
2275 }
2276 audit_log_end(audit_buf);
2277}
2278EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002279#endif /* CONFIG_AUDITSYSCALL */