blob: 1b2a72c8429cd31a747fcc9dfdbe5600bab8e676 [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;
Herbert Xu12a169e2008-10-01 07:03:24 -0700180static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static DEFINE_SPINLOCK(xfrm_state_gc_lock);
182
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800183int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800185int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800186void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700188static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
189{
190 struct xfrm_state_afinfo *afinfo;
191 if (unlikely(family >= NPROTO))
192 return NULL;
193 write_lock_bh(&xfrm_state_afinfo_lock);
194 afinfo = xfrm_state_afinfo[family];
195 if (unlikely(!afinfo))
196 write_unlock_bh(&xfrm_state_afinfo_lock);
197 return afinfo;
198}
199
200static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800201 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700202{
203 write_unlock_bh(&xfrm_state_afinfo_lock);
204}
205
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800206int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700207{
208 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800209 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700210 int err = 0;
211
212 if (unlikely(afinfo == NULL))
213 return -EAFNOSUPPORT;
214 typemap = afinfo->type_map;
215
216 if (likely(typemap[type->proto] == NULL))
217 typemap[type->proto] = type;
218 else
219 err = -EEXIST;
220 xfrm_state_unlock_afinfo(afinfo);
221 return err;
222}
223EXPORT_SYMBOL(xfrm_register_type);
224
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800225int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700226{
227 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800228 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700229 int err = 0;
230
231 if (unlikely(afinfo == NULL))
232 return -EAFNOSUPPORT;
233 typemap = afinfo->type_map;
234
235 if (unlikely(typemap[type->proto] != type))
236 err = -ENOENT;
237 else
238 typemap[type->proto] = NULL;
239 xfrm_state_unlock_afinfo(afinfo);
240 return err;
241}
242EXPORT_SYMBOL(xfrm_unregister_type);
243
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800244static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700245{
246 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800247 const struct xfrm_type **typemap;
248 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700249 int modload_attempted = 0;
250
251retry:
252 afinfo = xfrm_state_get_afinfo(family);
253 if (unlikely(afinfo == NULL))
254 return NULL;
255 typemap = afinfo->type_map;
256
257 type = typemap[proto];
258 if (unlikely(type && !try_module_get(type->owner)))
259 type = NULL;
260 if (!type && !modload_attempted) {
261 xfrm_state_put_afinfo(afinfo);
262 request_module("xfrm-type-%d-%d", family, proto);
263 modload_attempted = 1;
264 goto retry;
265 }
266
267 xfrm_state_put_afinfo(afinfo);
268 return type;
269}
270
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800271static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700272{
273 module_put(type->owner);
274}
275
276int xfrm_register_mode(struct xfrm_mode *mode, int family)
277{
278 struct xfrm_state_afinfo *afinfo;
279 struct xfrm_mode **modemap;
280 int err;
281
282 if (unlikely(mode->encap >= XFRM_MODE_MAX))
283 return -EINVAL;
284
285 afinfo = xfrm_state_lock_afinfo(family);
286 if (unlikely(afinfo == NULL))
287 return -EAFNOSUPPORT;
288
289 err = -EEXIST;
290 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700291 if (modemap[mode->encap])
292 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700293
Herbert Xu17c2a422007-10-17 21:33:12 -0700294 err = -ENOENT;
295 if (!try_module_get(afinfo->owner))
296 goto out;
297
298 mode->afinfo = afinfo;
299 modemap[mode->encap] = mode;
300 err = 0;
301
302out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700303 xfrm_state_unlock_afinfo(afinfo);
304 return err;
305}
306EXPORT_SYMBOL(xfrm_register_mode);
307
308int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
309{
310 struct xfrm_state_afinfo *afinfo;
311 struct xfrm_mode **modemap;
312 int err;
313
314 if (unlikely(mode->encap >= XFRM_MODE_MAX))
315 return -EINVAL;
316
317 afinfo = xfrm_state_lock_afinfo(family);
318 if (unlikely(afinfo == NULL))
319 return -EAFNOSUPPORT;
320
321 err = -ENOENT;
322 modemap = afinfo->mode_map;
323 if (likely(modemap[mode->encap] == mode)) {
324 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700325 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700326 err = 0;
327 }
328
329 xfrm_state_unlock_afinfo(afinfo);
330 return err;
331}
332EXPORT_SYMBOL(xfrm_unregister_mode);
333
334static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
335{
336 struct xfrm_state_afinfo *afinfo;
337 struct xfrm_mode *mode;
338 int modload_attempted = 0;
339
340 if (unlikely(encap >= XFRM_MODE_MAX))
341 return NULL;
342
343retry:
344 afinfo = xfrm_state_get_afinfo(family);
345 if (unlikely(afinfo == NULL))
346 return NULL;
347
348 mode = afinfo->mode_map[encap];
349 if (unlikely(mode && !try_module_get(mode->owner)))
350 mode = NULL;
351 if (!mode && !modload_attempted) {
352 xfrm_state_put_afinfo(afinfo);
353 request_module("xfrm-mode-%d-%d", family, encap);
354 modload_attempted = 1;
355 goto retry;
356 }
357
358 xfrm_state_put_afinfo(afinfo);
359 return mode;
360}
361
362static void xfrm_put_mode(struct xfrm_mode *mode)
363{
364 module_put(mode->owner);
365}
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367static void xfrm_state_gc_destroy(struct xfrm_state *x)
368{
David S. Millera47f0ce2006-08-24 03:54:22 -0700369 del_timer_sync(&x->timer);
370 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800371 kfree(x->aalg);
372 kfree(x->ealg);
373 kfree(x->calg);
374 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700375 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700376 if (x->inner_mode)
377 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700378 if (x->inner_mode_iaf)
379 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700380 if (x->outer_mode)
381 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 if (x->type) {
383 x->type->destructor(x);
384 xfrm_put_type(x->type);
385 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800386 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 kfree(x);
388}
389
David Howellsc4028952006-11-22 14:57:56 +0000390static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
Herbert Xu12a169e2008-10-01 07:03:24 -0700392 struct xfrm_state *x;
393 struct hlist_node *entry, *tmp;
394 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700397 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 spin_unlock_bh(&xfrm_state_gc_lock);
399
Herbert Xu12a169e2008-10-01 07:03:24 -0700400 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 wake_up(&km_waitq);
404}
405
406static inline unsigned long make_jiffies(long secs)
407{
408 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
409 return MAX_SCHEDULE_TIMEOUT-1;
410 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900411 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
414static void xfrm_timer_handler(unsigned long data)
415{
416 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800417 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 long next = LONG_MAX;
419 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600420 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 spin_lock(&x->lock);
423 if (x->km.state == XFRM_STATE_DEAD)
424 goto out;
425 if (x->km.state == XFRM_STATE_EXPIRED)
426 goto expired;
427 if (x->lft.hard_add_expires_seconds) {
428 long tmo = x->lft.hard_add_expires_seconds +
429 x->curlft.add_time - now;
430 if (tmo <= 0)
431 goto expired;
432 if (tmo < next)
433 next = tmo;
434 }
435 if (x->lft.hard_use_expires_seconds) {
436 long tmo = x->lft.hard_use_expires_seconds +
437 (x->curlft.use_time ? : now) - now;
438 if (tmo <= 0)
439 goto expired;
440 if (tmo < next)
441 next = tmo;
442 }
443 if (x->km.dying)
444 goto resched;
445 if (x->lft.soft_add_expires_seconds) {
446 long tmo = x->lft.soft_add_expires_seconds +
447 x->curlft.add_time - now;
448 if (tmo <= 0)
449 warn = 1;
450 else if (tmo < next)
451 next = tmo;
452 }
453 if (x->lft.soft_use_expires_seconds) {
454 long tmo = x->lft.soft_use_expires_seconds +
455 (x->curlft.use_time ? : now) - now;
456 if (tmo <= 0)
457 warn = 1;
458 else if (tmo < next)
459 next = tmo;
460 }
461
Herbert Xu4666faa2005-06-18 22:43:22 -0700462 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800464 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700466 if (next != LONG_MAX)
467 mod_timer(&x->timer, jiffies + make_jiffies(next));
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 goto out;
470
471expired:
472 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
473 x->km.state = XFRM_STATE_EXPIRED;
474 wake_up(&km_waitq);
475 next = 2;
476 goto resched;
477 }
Joy Latten161a09e2006-11-27 13:11:54 -0600478
479 err = __xfrm_state_delete(x);
480 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800481 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Joy Lattenab5f5e82007-09-17 11:51:22 -0700483 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400484 audit_get_loginuid(current),
485 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487out:
488 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
David S. Miller0ac84752006-03-20 19:18:23 -0800491static void xfrm_replay_timer_handler(unsigned long data);
492
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800493struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 struct xfrm_state *x;
496
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700497 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800500 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 atomic_set(&x->refcnt, 1);
502 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700503 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700504 INIT_HLIST_NODE(&x->bydst);
505 INIT_HLIST_NODE(&x->bysrc);
506 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800507 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
508 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
509 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800510 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 x->lft.soft_byte_limit = XFRM_INF;
512 x->lft.soft_packet_limit = XFRM_INF;
513 x->lft.hard_byte_limit = XFRM_INF;
514 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800515 x->replay_maxage = 0;
516 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700517 x->inner_mode = NULL;
518 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 spin_lock_init(&x->lock);
520 }
521 return x;
522}
523EXPORT_SYMBOL(xfrm_state_alloc);
524
525void __xfrm_state_destroy(struct xfrm_state *x)
526{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700527 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
529 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700530 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 spin_unlock_bh(&xfrm_state_gc_lock);
532 schedule_work(&xfrm_state_gc_work);
533}
534EXPORT_SYMBOL(__xfrm_state_destroy);
535
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800536int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700538 int err = -ESRCH;
539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (x->km.state != XFRM_STATE_DEAD) {
541 x->km.state = XFRM_STATE_DEAD;
542 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700543 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700544 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700545 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700546 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700547 hlist_del(&x->byspi);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800548 init_net.xfrm.state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 /* All xfrm_state objects are created by xfrm_state_alloc.
552 * The xfrm_state_alloc call gives a reference, and that
553 * is what we are dropping here.
554 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800555 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700556 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700558
559 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800561EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700563int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700565 int err;
566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700568 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700570
571 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572}
573EXPORT_SYMBOL(xfrm_state_delete);
574
Joy Latten4aa2e622007-06-04 19:05:57 -0400575#ifdef CONFIG_SECURITY_NETWORK_XFRM
576static inline int
577xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Joy Latten4aa2e622007-06-04 19:05:57 -0400579 int i, err = 0;
580
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800581 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400582 struct hlist_node *entry;
583 struct xfrm_state *x;
584
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800585 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400586 if (xfrm_id_proto_match(x->id.proto, proto) &&
587 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700588 xfrm_audit_state_delete(x, 0,
589 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400590 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700591 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400592 return err;
593 }
594 }
595 }
596
597 return err;
598}
599#else
600static inline int
601xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
602{
603 return 0;
604}
605#endif
606
607int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
608{
609 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400612 err = xfrm_state_flush_secctx_check(proto, audit_info);
613 if (err)
614 goto out;
615
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800616 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700617 struct hlist_node *entry;
618 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800620 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700622 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 xfrm_state_hold(x);
624 spin_unlock_bh(&xfrm_state_lock);
625
Joy Latten161a09e2006-11-27 13:11:54 -0600626 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700627 xfrm_audit_state_delete(x, err ? 0 : 1,
628 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400629 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700630 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 xfrm_state_put(x);
632
633 spin_lock_bh(&xfrm_state_lock);
634 goto restart;
635 }
636 }
637 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400638 err = 0;
639
640out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 spin_unlock_bh(&xfrm_state_lock);
642 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400643 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645EXPORT_SYMBOL(xfrm_state_flush);
646
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700647void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700648{
649 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800650 si->sadcnt = init_net.xfrm.state_num;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800651 si->sadhcnt = init_net.xfrm.state_hmask;
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700652 si->sadhmcnt = xfrm_state_hashmax;
653 spin_unlock_bh(&xfrm_state_lock);
654}
655EXPORT_SYMBOL(xfrm_sad_getinfo);
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657static int
658xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
659 struct xfrm_tmpl *tmpl,
660 xfrm_address_t *daddr, xfrm_address_t *saddr,
661 unsigned short family)
662{
663 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
664 if (!afinfo)
665 return -1;
666 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
667 xfrm_state_put_afinfo(afinfo);
668 return 0;
669}
670
Al Viroa94cfd12006-09-27 18:47:24 -0700671static 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 -0700672{
673 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
674 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700675 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700676
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800677 hlist_for_each_entry(x, entry, init_net.xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700678 if (x->props.family != family ||
679 x->id.spi != spi ||
680 x->id.proto != proto)
681 continue;
682
683 switch (family) {
684 case AF_INET:
685 if (x->id.daddr.a4 != daddr->a4)
686 continue;
687 break;
688 case AF_INET6:
689 if (!ipv6_addr_equal((struct in6_addr *)daddr,
690 (struct in6_addr *)
691 x->id.daddr.a6))
692 continue;
693 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700694 }
David S. Milleredcd5822006-08-24 00:42:45 -0700695
696 xfrm_state_hold(x);
697 return x;
698 }
699
700 return NULL;
701}
702
703static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
704{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700705 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700706 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700707 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700708
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800709 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700710 if (x->props.family != family ||
711 x->id.proto != proto)
712 continue;
713
714 switch (family) {
715 case AF_INET:
716 if (x->id.daddr.a4 != daddr->a4 ||
717 x->props.saddr.a4 != saddr->a4)
718 continue;
719 break;
720 case AF_INET6:
721 if (!ipv6_addr_equal((struct in6_addr *)daddr,
722 (struct in6_addr *)
723 x->id.daddr.a6) ||
724 !ipv6_addr_equal((struct in6_addr *)saddr,
725 (struct in6_addr *)
726 x->props.saddr.a6))
727 continue;
728 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700729 }
David S. Milleredcd5822006-08-24 00:42:45 -0700730
731 xfrm_state_hold(x);
732 return x;
733 }
734
735 return NULL;
736}
737
738static inline struct xfrm_state *
739__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
740{
741 if (use_spi)
742 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
743 x->id.proto, family);
744 else
745 return __xfrm_state_lookup_byaddr(&x->id.daddr,
746 &x->props.saddr,
747 x->id.proto, family);
748}
749
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700750static void xfrm_hash_grow_check(int have_hash_collision)
751{
752 if (have_hash_collision &&
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800753 (init_net.xfrm.state_hmask + 1) < xfrm_state_hashmax &&
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800754 init_net.xfrm.state_num > init_net.xfrm.state_hmask)
Alexey Dobriyan63082732008-11-25 17:19:07 -0800755 schedule_work(&init_net.xfrm.state_hash_work);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700756}
757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900759xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 struct flowi *fl, struct xfrm_tmpl *tmpl,
761 struct xfrm_policy *pol, int *err,
762 unsigned short family)
763{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800764 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700765 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700766 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 int acquire_in_progress = 0;
768 int error = 0;
769 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900770
David S. Miller37b08e32008-09-02 20:14:15 -0700771 to_put = NULL;
772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800774 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800775 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (x->props.family == family &&
777 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700778 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 xfrm_state_addr_check(x, daddr, saddr, family) &&
780 tmpl->mode == x->props.mode &&
781 tmpl->id.proto == x->id.proto &&
782 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
783 /* Resolution logic:
784 1. There is a valid state with matching selector.
785 Done.
786 2. Valid state with inappropriate selector. Skip.
787
788 Entering area of "sysdeps".
789
790 3. If state is not valid, selector is temporary,
791 it selects only session which triggered
792 previous resolution. Key manager will do
793 something to install a state with proper
794 selector.
795 */
796 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700797 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700798 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 continue;
800 if (!best ||
801 best->km.dying > x->km.dying ||
802 (best->km.dying == x->km.dying &&
803 best->curlft.add_time < x->curlft.add_time))
804 best = x;
805 } else if (x->km.state == XFRM_STATE_ACQ) {
806 acquire_in_progress = 1;
807 } else if (x->km.state == XFRM_STATE_ERROR ||
808 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700809 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700810 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 error = -ESRCH;
812 }
813 }
814 }
815
816 x = best;
817 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700818 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700819 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
820 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700821 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 error = -EEXIST;
823 goto out;
824 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800825 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (x == NULL) {
827 error = -ENOMEM;
828 goto out;
829 }
830 /* Initialize temporary selector matching only
831 * to current session. */
832 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
833
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700834 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
835 if (error) {
836 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700837 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700838 x = NULL;
839 goto out;
840 }
841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (km_query(x, tmpl, pol) == 0) {
843 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800844 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800845 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700846 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800847 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (x->id.spi) {
849 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800850 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
David S. Miller01e67d02007-05-25 00:41:38 -0700852 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
853 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 add_timer(&x->timer);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800855 init_net.xfrm.state_num++;
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700856 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 } else {
858 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700859 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 x = NULL;
861 error = -ESRCH;
862 }
863 }
864out:
865 if (x)
866 xfrm_state_hold(x);
867 else
868 *err = acquire_in_progress ? -EAGAIN : error;
869 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700870 if (to_put)
871 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return x;
873}
874
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700875struct xfrm_state *
876xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
877 unsigned short family, u8 mode, u8 proto, u32 reqid)
878{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800879 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700880 struct xfrm_state *rx = NULL, *x = NULL;
881 struct hlist_node *entry;
882
883 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800884 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800885 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700886 if (x->props.family == family &&
887 x->props.reqid == reqid &&
888 !(x->props.flags & XFRM_STATE_WILDRECV) &&
889 xfrm_state_addr_check(x, daddr, saddr, family) &&
890 mode == x->props.mode &&
891 proto == x->id.proto &&
892 x->km.state == XFRM_STATE_VALID) {
893 rx = x;
894 break;
895 }
896 }
897
898 if (rx)
899 xfrm_state_hold(rx);
900 spin_unlock(&xfrm_state_lock);
901
902
903 return rx;
904}
905EXPORT_SYMBOL(xfrm_stateonly_find);
906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907static void __xfrm_state_insert(struct xfrm_state *x)
908{
David S. Millera624c102006-08-24 03:24:33 -0700909 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
David S. Miller9d4a7062006-08-24 03:18:09 -0700911 x->genid = ++xfrm_state_genid;
912
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800913 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800914
David S. Millerc1969f22006-08-24 04:00:03 -0700915 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
916 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800917 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700919 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800920 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700922 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700923 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
924 x->props.family);
925
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800926 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700927 }
928
David S. Millera47f0ce2006-08-24 03:54:22 -0700929 mod_timer(&x->timer, jiffies + HZ);
930 if (x->replay_maxage)
931 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700934
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800935 init_net.xfrm.state_num++;
David S. Millerf034b5d2006-08-24 03:08:07 -0700936
David S. Miller918049f2006-10-12 22:03:24 -0700937 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938}
939
David S. Millerc7f5ea32006-08-24 03:29:04 -0700940/* xfrm_state_lock is held */
941static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
942{
943 unsigned short family = xnew->props.family;
944 u32 reqid = xnew->props.reqid;
945 struct xfrm_state *x;
946 struct hlist_node *entry;
947 unsigned int h;
948
David S. Millerc1969f22006-08-24 04:00:03 -0700949 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800950 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700951 if (x->props.family == family &&
952 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700953 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
954 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700955 x->genid = xfrm_state_genid;
956 }
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959void xfrm_state_insert(struct xfrm_state *x)
960{
961 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700962 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 __xfrm_state_insert(x);
964 spin_unlock_bh(&xfrm_state_lock);
965}
966EXPORT_SYMBOL(xfrm_state_insert);
967
David S. Miller27708342006-08-24 00:13:10 -0700968/* xfrm_state_lock is held */
969static 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)
970{
David S. Millerc1969f22006-08-24 04:00:03 -0700971 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700972 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700973 struct xfrm_state *x;
974
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800975 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700976 if (x->props.reqid != reqid ||
977 x->props.mode != mode ||
978 x->props.family != family ||
979 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700980 x->id.spi != 0 ||
981 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700982 continue;
983
984 switch (family) {
985 case AF_INET:
986 if (x->id.daddr.a4 != daddr->a4 ||
987 x->props.saddr.a4 != saddr->a4)
988 continue;
989 break;
990 case AF_INET6:
991 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
992 (struct in6_addr *)daddr) ||
993 !ipv6_addr_equal((struct in6_addr *)
994 x->props.saddr.a6,
995 (struct in6_addr *)saddr))
996 continue;
997 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700998 }
David S. Miller27708342006-08-24 00:13:10 -0700999
1000 xfrm_state_hold(x);
1001 return x;
1002 }
1003
1004 if (!create)
1005 return NULL;
1006
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001007 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001008 if (likely(x)) {
1009 switch (family) {
1010 case AF_INET:
1011 x->sel.daddr.a4 = daddr->a4;
1012 x->sel.saddr.a4 = saddr->a4;
1013 x->sel.prefixlen_d = 32;
1014 x->sel.prefixlen_s = 32;
1015 x->props.saddr.a4 = saddr->a4;
1016 x->id.daddr.a4 = daddr->a4;
1017 break;
1018
1019 case AF_INET6:
1020 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1021 (struct in6_addr *)daddr);
1022 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1023 (struct in6_addr *)saddr);
1024 x->sel.prefixlen_d = 128;
1025 x->sel.prefixlen_s = 128;
1026 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1027 (struct in6_addr *)saddr);
1028 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1029 (struct in6_addr *)daddr);
1030 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001031 }
David S. Miller27708342006-08-24 00:13:10 -07001032
1033 x->km.state = XFRM_STATE_ACQ;
1034 x->id.proto = proto;
1035 x->props.family = family;
1036 x->props.mode = mode;
1037 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001038 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001039 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001040 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001041 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001042 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001043 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001044 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001045 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001046
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08001047 init_net.xfrm.state_num++;
David S. Miller918049f2006-10-12 22:03:24 -07001048
1049 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001050 }
1051
1052 return x;
1053}
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1056
1057int xfrm_state_add(struct xfrm_state *x)
1058{
David S. Miller37b08e32008-09-02 20:14:15 -07001059 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 int family;
1061 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001062 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
David S. Miller37b08e32008-09-02 20:14:15 -07001066 to_put = NULL;
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 spin_lock_bh(&xfrm_state_lock);
1069
David S. Milleredcd5822006-08-24 00:42:45 -07001070 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001072 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 x1 = NULL;
1074 err = -EEXIST;
1075 goto out;
1076 }
1077
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001078 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001080 if (x1 && ((x1->id.proto != x->id.proto) ||
1081 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001082 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 x1 = NULL;
1084 }
1085 }
1086
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001087 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001088 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1089 x->id.proto,
1090 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
David S. Millerc7f5ea32006-08-24 03:29:04 -07001092 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 __xfrm_state_insert(x);
1094 err = 0;
1095
1096out:
1097 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 if (x1) {
1100 xfrm_state_delete(x1);
1101 xfrm_state_put(x1);
1102 }
1103
David S. Miller37b08e32008-09-02 20:14:15 -07001104 if (to_put)
1105 xfrm_state_put(to_put);
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return err;
1108}
1109EXPORT_SYMBOL(xfrm_state_add);
1110
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001111#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001112static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001113{
1114 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001115 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001116 if (!x)
1117 goto error;
1118
1119 memcpy(&x->id, &orig->id, sizeof(x->id));
1120 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1121 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1122 x->props.mode = orig->props.mode;
1123 x->props.replay_window = orig->props.replay_window;
1124 x->props.reqid = orig->props.reqid;
1125 x->props.family = orig->props.family;
1126 x->props.saddr = orig->props.saddr;
1127
1128 if (orig->aalg) {
1129 x->aalg = xfrm_algo_clone(orig->aalg);
1130 if (!x->aalg)
1131 goto error;
1132 }
1133 x->props.aalgo = orig->props.aalgo;
1134
1135 if (orig->ealg) {
1136 x->ealg = xfrm_algo_clone(orig->ealg);
1137 if (!x->ealg)
1138 goto error;
1139 }
1140 x->props.ealgo = orig->props.ealgo;
1141
1142 if (orig->calg) {
1143 x->calg = xfrm_algo_clone(orig->calg);
1144 if (!x->calg)
1145 goto error;
1146 }
1147 x->props.calgo = orig->props.calgo;
1148
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001149 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001150 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1151 if (!x->encap)
1152 goto error;
1153 }
1154
1155 if (orig->coaddr) {
1156 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1157 GFP_KERNEL);
1158 if (!x->coaddr)
1159 goto error;
1160 }
1161
1162 err = xfrm_init_state(x);
1163 if (err)
1164 goto error;
1165
1166 x->props.flags = orig->props.flags;
1167
1168 x->curlft.add_time = orig->curlft.add_time;
1169 x->km.state = orig->km.state;
1170 x->km.seq = orig->km.seq;
1171
1172 return x;
1173
1174 error:
1175 if (errp)
1176 *errp = err;
1177 if (x) {
1178 kfree(x->aalg);
1179 kfree(x->ealg);
1180 kfree(x->calg);
1181 kfree(x->encap);
1182 kfree(x->coaddr);
1183 }
1184 kfree(x);
1185 return NULL;
1186}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001187
1188/* xfrm_state_lock is held */
1189struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1190{
1191 unsigned int h;
1192 struct xfrm_state *x;
1193 struct hlist_node *entry;
1194
1195 if (m->reqid) {
1196 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1197 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001198 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001199 if (x->props.mode != m->mode ||
1200 x->id.proto != m->proto)
1201 continue;
1202 if (m->reqid && x->props.reqid != m->reqid)
1203 continue;
1204 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1205 m->old_family) ||
1206 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1207 m->old_family))
1208 continue;
1209 xfrm_state_hold(x);
1210 return x;
1211 }
1212 } else {
1213 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1214 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001215 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001216 if (x->props.mode != m->mode ||
1217 x->id.proto != m->proto)
1218 continue;
1219 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1220 m->old_family) ||
1221 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1222 m->old_family))
1223 continue;
1224 xfrm_state_hold(x);
1225 return x;
1226 }
1227 }
1228
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001229 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001230}
1231EXPORT_SYMBOL(xfrm_migrate_state_find);
1232
1233struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1234 struct xfrm_migrate *m)
1235{
1236 struct xfrm_state *xc;
1237 int err;
1238
1239 xc = xfrm_state_clone(x, &err);
1240 if (!xc)
1241 return NULL;
1242
1243 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1244 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1245
1246 /* add state */
1247 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1248 /* a care is needed when the destination address of the
1249 state is to be updated as it is a part of triplet */
1250 xfrm_state_insert(xc);
1251 } else {
1252 if ((err = xfrm_state_add(xc)) < 0)
1253 goto error;
1254 }
1255
1256 return xc;
1257error:
1258 kfree(xc);
1259 return NULL;
1260}
1261EXPORT_SYMBOL(xfrm_state_migrate);
1262#endif
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264int xfrm_state_update(struct xfrm_state *x)
1265{
David S. Miller37b08e32008-09-02 20:14:15 -07001266 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001268 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
David S. Miller37b08e32008-09-02 20:14:15 -07001270 to_put = NULL;
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001273 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
1275 err = -ESRCH;
1276 if (!x1)
1277 goto out;
1278
1279 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001280 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 err = -EEXIST;
1282 goto out;
1283 }
1284
1285 if (x1->km.state == XFRM_STATE_ACQ) {
1286 __xfrm_state_insert(x);
1287 x = NULL;
1288 }
1289 err = 0;
1290
1291out:
1292 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
David S. Miller37b08e32008-09-02 20:14:15 -07001294 if (to_put)
1295 xfrm_state_put(to_put);
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (err)
1298 return err;
1299
1300 if (!x) {
1301 xfrm_state_delete(x1);
1302 xfrm_state_put(x1);
1303 return 0;
1304 }
1305
1306 err = -EINVAL;
1307 spin_lock_bh(&x1->lock);
1308 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1309 if (x->encap && x1->encap)
1310 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001311 if (x->coaddr && x1->coaddr) {
1312 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1313 }
1314 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1315 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1317 x1->km.dying = 0;
1318
David S. Millera47f0ce2006-08-24 03:54:22 -07001319 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (x1->curlft.use_time)
1321 xfrm_state_check_expire(x1);
1322
1323 err = 0;
1324 }
1325 spin_unlock_bh(&x1->lock);
1326
1327 xfrm_state_put(x1);
1328
1329 return err;
1330}
1331EXPORT_SYMBOL(xfrm_state_update);
1332
1333int xfrm_state_check_expire(struct xfrm_state *x)
1334{
1335 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001336 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 if (x->km.state != XFRM_STATE_VALID)
1339 return -EINVAL;
1340
1341 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1342 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001343 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001344 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 return -EINVAL;
1346 }
1347
1348 if (!x->km.dying &&
1349 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001350 x->curlft.packets >= x->lft.soft_packet_limit)) {
1351 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001352 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return 0;
1355}
1356EXPORT_SYMBOL(xfrm_state_check_expire);
1357
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001359xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 unsigned short family)
1361{
1362 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
1364 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001365 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 return x;
1368}
1369EXPORT_SYMBOL(xfrm_state_lookup);
1370
1371struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001372xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1373 u8 proto, unsigned short family)
1374{
1375 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001376
1377 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001378 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001379 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001380 return x;
1381}
1382EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1383
1384struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001385xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1386 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 int create, unsigned short family)
1388{
1389 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001392 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 return x;
1396}
1397EXPORT_SYMBOL(xfrm_find_acq);
1398
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001399#ifdef CONFIG_XFRM_SUB_POLICY
1400int
1401xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1402 unsigned short family)
1403{
1404 int err = 0;
1405 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1406 if (!afinfo)
1407 return -EAFNOSUPPORT;
1408
1409 spin_lock_bh(&xfrm_state_lock);
1410 if (afinfo->tmpl_sort)
1411 err = afinfo->tmpl_sort(dst, src, n);
1412 spin_unlock_bh(&xfrm_state_lock);
1413 xfrm_state_put_afinfo(afinfo);
1414 return err;
1415}
1416EXPORT_SYMBOL(xfrm_tmpl_sort);
1417
1418int
1419xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1420 unsigned short family)
1421{
1422 int err = 0;
1423 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1424 if (!afinfo)
1425 return -EAFNOSUPPORT;
1426
1427 spin_lock_bh(&xfrm_state_lock);
1428 if (afinfo->state_sort)
1429 err = afinfo->state_sort(dst, src, n);
1430 spin_unlock_bh(&xfrm_state_lock);
1431 xfrm_state_put_afinfo(afinfo);
1432 return err;
1433}
1434EXPORT_SYMBOL(xfrm_state_sort);
1435#endif
1436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437/* Silly enough, but I'm lazy to build resolution list */
1438
1439static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1440{
1441 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Alexey Dobriyan529983e2008-11-25 17:18:12 -08001443 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001444 struct hlist_node *entry;
1445 struct xfrm_state *x;
1446
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001447 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001448 if (x->km.seq == seq &&
1449 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 xfrm_state_hold(x);
1451 return x;
1452 }
1453 }
1454 }
1455 return NULL;
1456}
1457
1458struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1459{
1460 struct xfrm_state *x;
1461
1462 spin_lock_bh(&xfrm_state_lock);
1463 x = __xfrm_find_acq_byseq(seq);
1464 spin_unlock_bh(&xfrm_state_lock);
1465 return x;
1466}
1467EXPORT_SYMBOL(xfrm_find_acq_byseq);
1468
1469u32 xfrm_get_acqseq(void)
1470{
1471 u32 res;
1472 static u32 acqseq;
1473 static DEFINE_SPINLOCK(acqseq_lock);
1474
1475 spin_lock_bh(&acqseq_lock);
1476 res = (++acqseq ? : ++acqseq);
1477 spin_unlock_bh(&acqseq_lock);
1478 return res;
1479}
1480EXPORT_SYMBOL(xfrm_get_acqseq);
1481
Herbert Xu658b2192007-10-09 13:29:52 -07001482int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
David S. Millerf034b5d2006-08-24 03:08:07 -07001484 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001486 int err = -ENOENT;
1487 __be32 minspi = htonl(low);
1488 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Herbert Xu658b2192007-10-09 13:29:52 -07001490 spin_lock_bh(&x->lock);
1491 if (x->km.state == XFRM_STATE_DEAD)
1492 goto unlock;
1493
1494 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001496 goto unlock;
1497
1498 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 if (minspi == maxspi) {
1501 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1502 if (x0) {
1503 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001504 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 }
1506 x->id.spi = minspi;
1507 } else {
1508 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001509 for (h=0; h<high-low+1; h++) {
1510 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1512 if (x0 == NULL) {
1513 x->id.spi = htonl(spi);
1514 break;
1515 }
1516 xfrm_state_put(x0);
1517 }
1518 }
1519 if (x->id.spi) {
1520 spin_lock_bh(&xfrm_state_lock);
1521 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08001522 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001524
1525 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 }
Herbert Xu658b2192007-10-09 13:29:52 -07001527
1528unlock:
1529 spin_unlock_bh(&x->lock);
1530
1531 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532}
1533EXPORT_SYMBOL(xfrm_alloc_spi);
1534
Timo Teras4c563f72008-02-28 21:31:08 -08001535int xfrm_state_walk(struct xfrm_state_walk *walk,
1536 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 void *data)
1538{
Herbert Xu12a169e2008-10-01 07:03:24 -07001539 struct xfrm_state *state;
1540 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 int err = 0;
1542
Herbert Xu12a169e2008-10-01 07:03:24 -07001543 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001544 return 0;
1545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001547 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001548 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001549 else
1550 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001551 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001552 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001553 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001554 state = container_of(x, struct xfrm_state, km);
1555 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001556 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001557 err = func(state, walk->seq, data);
1558 if (err) {
1559 list_move_tail(&walk->all, &x->all);
1560 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001562 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001564 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 err = -ENOENT;
1566 goto out;
1567 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001568 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569out:
1570 spin_unlock_bh(&xfrm_state_lock);
1571 return err;
1572}
1573EXPORT_SYMBOL(xfrm_state_walk);
1574
Herbert Xu5c182452008-09-22 19:48:19 -07001575void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1576{
Herbert Xu12a169e2008-10-01 07:03:24 -07001577 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001578 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001579 walk->state = XFRM_STATE_DEAD;
1580 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001581}
1582EXPORT_SYMBOL(xfrm_state_walk_init);
1583
Herbert Xuabb81c42008-09-09 19:58:29 -07001584void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1585{
Herbert Xu12a169e2008-10-01 07:03:24 -07001586 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001587 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001588
Herbert Xu12a169e2008-10-01 07:03:24 -07001589 spin_lock_bh(&xfrm_state_lock);
1590 list_del(&walk->all);
1591 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001592}
1593EXPORT_SYMBOL(xfrm_state_walk_done);
1594
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001595
1596void xfrm_replay_notify(struct xfrm_state *x, int event)
1597{
1598 struct km_event c;
1599 /* we send notify messages in case
1600 * 1. we updated on of the sequence numbers, and the seqno difference
1601 * is at least x->replay_maxdiff, in this case we also update the
1602 * timeout of our timer function
1603 * 2. if x->replay_maxage has elapsed since last update,
1604 * and there were changes
1605 *
1606 * The state structure must be locked!
1607 */
1608
1609 switch (event) {
1610 case XFRM_REPLAY_UPDATE:
1611 if (x->replay_maxdiff &&
1612 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001613 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1614 if (x->xflags & XFRM_TIME_DEFER)
1615 event = XFRM_REPLAY_TIMEOUT;
1616 else
1617 return;
1618 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001619
1620 break;
1621
1622 case XFRM_REPLAY_TIMEOUT:
1623 if ((x->replay.seq == x->preplay.seq) &&
1624 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001625 (x->replay.oseq == x->preplay.oseq)) {
1626 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001627 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001628 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001629
1630 break;
1631 }
1632
1633 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1634 c.event = XFRM_MSG_NEWAE;
1635 c.data.aevent = event;
1636 km_state_notify(x, &c);
1637
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001638 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001639 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001640 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001641}
1642
1643static void xfrm_replay_timer_handler(unsigned long data)
1644{
1645 struct xfrm_state *x = (struct xfrm_state*)data;
1646
1647 spin_lock(&x->lock);
1648
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001649 if (x->km.state == XFRM_STATE_VALID) {
1650 if (xfrm_aevent_is_on())
1651 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1652 else
1653 x->xflags |= XFRM_TIME_DEFER;
1654 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001655
1656 spin_unlock(&x->lock);
1657}
1658
Paul Mooreafeb14b2007-12-21 14:58:11 -08001659int xfrm_replay_check(struct xfrm_state *x,
1660 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661{
1662 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001663 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
1665 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001666 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 if (likely(seq > x->replay.seq))
1669 return 0;
1670
1671 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001672 if (diff >= min_t(unsigned int, x->props.replay_window,
1673 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001675 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 }
1677
1678 if (x->replay.bitmap & (1U << diff)) {
1679 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001680 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
1682 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001683
1684err:
1685 xfrm_audit_state_replay(x, skb, net_seq);
1686 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
Al Viro61f46272006-09-27 18:48:33 -07001689void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690{
1691 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001692 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 if (seq > x->replay.seq) {
1695 diff = seq - x->replay.seq;
1696 if (diff < x->props.replay_window)
1697 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1698 else
1699 x->replay.bitmap = 1;
1700 x->replay.seq = seq;
1701 } else {
1702 diff = x->replay.seq - seq;
1703 x->replay.bitmap |= (1U << diff);
1704 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001705
1706 if (xfrm_aevent_is_on())
1707 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
Denis Chengdf018122007-12-07 00:51:11 -08001710static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711static DEFINE_RWLOCK(xfrm_km_lock);
1712
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001713void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 struct xfrm_mgr *km;
1716
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001717 read_lock(&xfrm_km_lock);
1718 list_for_each_entry(km, &xfrm_km_list, list)
1719 if (km->notify_policy)
1720 km->notify_policy(xp, dir, c);
1721 read_unlock(&xfrm_km_lock);
1722}
1723
1724void km_state_notify(struct xfrm_state *x, struct km_event *c)
1725{
1726 struct xfrm_mgr *km;
1727 read_lock(&xfrm_km_lock);
1728 list_for_each_entry(km, &xfrm_km_list, list)
1729 if (km->notify)
1730 km->notify(x, c);
1731 read_unlock(&xfrm_km_lock);
1732}
1733
1734EXPORT_SYMBOL(km_policy_notify);
1735EXPORT_SYMBOL(km_state_notify);
1736
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001737void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001738{
1739 struct km_event c;
1740
Herbert Xubf088672005-06-18 22:44:00 -07001741 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001742 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001743 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001744 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
1746 if (hard)
1747 wake_up(&km_waitq);
1748}
1749
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001750EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001751/*
1752 * We send to all registered managers regardless of failure
1753 * We are happy with one success
1754*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001755int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001757 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 struct xfrm_mgr *km;
1759
1760 read_lock(&xfrm_km_lock);
1761 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001762 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1763 if (!acqret)
1764 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 }
1766 read_unlock(&xfrm_km_lock);
1767 return err;
1768}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001769EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
Al Viro5d36b182006-11-08 00:24:06 -08001771int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772{
1773 int err = -EINVAL;
1774 struct xfrm_mgr *km;
1775
1776 read_lock(&xfrm_km_lock);
1777 list_for_each_entry(km, &xfrm_km_list, list) {
1778 if (km->new_mapping)
1779 err = km->new_mapping(x, ipaddr, sport);
1780 if (!err)
1781 break;
1782 }
1783 read_unlock(&xfrm_km_lock);
1784 return err;
1785}
1786EXPORT_SYMBOL(km_new_mapping);
1787
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001788void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001790 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Herbert Xubf088672005-06-18 22:44:00 -07001792 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001793 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001794 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001795 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797 if (hard)
1798 wake_up(&km_waitq);
1799}
David S. Millera70fcb02006-03-20 19:18:52 -08001800EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001802#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001803int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001804 struct xfrm_migrate *m, int num_migrate,
1805 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001806{
1807 int err = -EINVAL;
1808 int ret;
1809 struct xfrm_mgr *km;
1810
1811 read_lock(&xfrm_km_lock);
1812 list_for_each_entry(km, &xfrm_km_list, list) {
1813 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001814 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001815 if (!ret)
1816 err = ret;
1817 }
1818 }
1819 read_unlock(&xfrm_km_lock);
1820 return err;
1821}
1822EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001823#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001824
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001825int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1826{
1827 int err = -EINVAL;
1828 int ret;
1829 struct xfrm_mgr *km;
1830
1831 read_lock(&xfrm_km_lock);
1832 list_for_each_entry(km, &xfrm_km_list, list) {
1833 if (km->report) {
1834 ret = km->report(proto, sel, addr);
1835 if (!ret)
1836 err = ret;
1837 }
1838 }
1839 read_unlock(&xfrm_km_lock);
1840 return err;
1841}
1842EXPORT_SYMBOL(km_report);
1843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1845{
1846 int err;
1847 u8 *data;
1848 struct xfrm_mgr *km;
1849 struct xfrm_policy *pol = NULL;
1850
1851 if (optlen <= 0 || optlen > PAGE_SIZE)
1852 return -EMSGSIZE;
1853
1854 data = kmalloc(optlen, GFP_KERNEL);
1855 if (!data)
1856 return -ENOMEM;
1857
1858 err = -EFAULT;
1859 if (copy_from_user(data, optval, optlen))
1860 goto out;
1861
1862 err = -EINVAL;
1863 read_lock(&xfrm_km_lock);
1864 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001865 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 optlen, &err);
1867 if (err >= 0)
1868 break;
1869 }
1870 read_unlock(&xfrm_km_lock);
1871
1872 if (err >= 0) {
1873 xfrm_sk_policy_insert(sk, err, pol);
1874 xfrm_pol_put(pol);
1875 err = 0;
1876 }
1877
1878out:
1879 kfree(data);
1880 return err;
1881}
1882EXPORT_SYMBOL(xfrm_user_policy);
1883
1884int xfrm_register_km(struct xfrm_mgr *km)
1885{
1886 write_lock_bh(&xfrm_km_lock);
1887 list_add_tail(&km->list, &xfrm_km_list);
1888 write_unlock_bh(&xfrm_km_lock);
1889 return 0;
1890}
1891EXPORT_SYMBOL(xfrm_register_km);
1892
1893int xfrm_unregister_km(struct xfrm_mgr *km)
1894{
1895 write_lock_bh(&xfrm_km_lock);
1896 list_del(&km->list);
1897 write_unlock_bh(&xfrm_km_lock);
1898 return 0;
1899}
1900EXPORT_SYMBOL(xfrm_unregister_km);
1901
1902int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1903{
1904 int err = 0;
1905 if (unlikely(afinfo == NULL))
1906 return -EINVAL;
1907 if (unlikely(afinfo->family >= NPROTO))
1908 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001909 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1911 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001912 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001914 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 return err;
1916}
1917EXPORT_SYMBOL(xfrm_state_register_afinfo);
1918
1919int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1920{
1921 int err = 0;
1922 if (unlikely(afinfo == NULL))
1923 return -EINVAL;
1924 if (unlikely(afinfo->family >= NPROTO))
1925 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001926 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1928 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1929 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001930 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001933 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 return err;
1935}
1936EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1937
Herbert Xu17c2a422007-10-17 21:33:12 -07001938static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
1940 struct xfrm_state_afinfo *afinfo;
1941 if (unlikely(family >= NPROTO))
1942 return NULL;
1943 read_lock(&xfrm_state_afinfo_lock);
1944 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001945 if (unlikely(!afinfo))
1946 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return afinfo;
1948}
1949
Herbert Xu17c2a422007-10-17 21:33:12 -07001950static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001951 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952{
Herbert Xu546be242006-05-27 23:03:58 -07001953 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954}
1955
1956/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1957void xfrm_state_delete_tunnel(struct xfrm_state *x)
1958{
1959 if (x->tunnel) {
1960 struct xfrm_state *t = x->tunnel;
1961
1962 if (atomic_read(&t->tunnel_users) == 2)
1963 xfrm_state_delete(t);
1964 atomic_dec(&t->tunnel_users);
1965 xfrm_state_put(t);
1966 x->tunnel = NULL;
1967 }
1968}
1969EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1970
1971int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1972{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001973 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
Patrick McHardyc5c25232007-04-09 11:47:18 -07001975 spin_lock_bh(&x->lock);
1976 if (x->km.state == XFRM_STATE_VALID &&
1977 x->type && x->type->get_mtu)
1978 res = x->type->get_mtu(x, mtu);
1979 else
Patrick McHardy28121612007-06-18 22:30:15 -07001980 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001981 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return res;
1983}
1984
Herbert Xu72cb6962005-06-20 13:18:08 -07001985int xfrm_init_state(struct xfrm_state *x)
1986{
Herbert Xud094cd82005-06-20 13:19:41 -07001987 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001988 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001989 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001990 int err;
1991
Herbert Xud094cd82005-06-20 13:19:41 -07001992 err = -EAFNOSUPPORT;
1993 afinfo = xfrm_state_get_afinfo(family);
1994 if (!afinfo)
1995 goto error;
1996
1997 err = 0;
1998 if (afinfo->init_flags)
1999 err = afinfo->init_flags(x);
2000
2001 xfrm_state_put_afinfo(afinfo);
2002
2003 if (err)
2004 goto error;
2005
2006 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002007
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002008 if (x->sel.family != AF_UNSPEC) {
2009 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2010 if (inner_mode == NULL)
2011 goto error;
2012
2013 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2014 family != x->sel.family) {
2015 xfrm_put_mode(inner_mode);
2016 goto error;
2017 }
2018
2019 x->inner_mode = inner_mode;
2020 } else {
2021 struct xfrm_mode *inner_mode_iaf;
2022
2023 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2024 if (inner_mode == NULL)
2025 goto error;
2026
2027 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2028 xfrm_put_mode(inner_mode);
2029 goto error;
2030 }
2031
2032 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2033 if (inner_mode_iaf == NULL)
2034 goto error;
2035
2036 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2037 xfrm_put_mode(inner_mode_iaf);
2038 goto error;
2039 }
2040
2041 if (x->props.family == AF_INET) {
2042 x->inner_mode = inner_mode;
2043 x->inner_mode_iaf = inner_mode_iaf;
2044 } else {
2045 x->inner_mode = inner_mode_iaf;
2046 x->inner_mode_iaf = inner_mode;
2047 }
2048 }
Herbert Xu13996372007-10-17 21:35:51 -07002049
Herbert Xud094cd82005-06-20 13:19:41 -07002050 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002051 if (x->type == NULL)
2052 goto error;
2053
2054 err = x->type->init_state(x);
2055 if (err)
2056 goto error;
2057
Herbert Xu13996372007-10-17 21:35:51 -07002058 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2059 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002060 goto error;
2061
Herbert Xu72cb6962005-06-20 13:18:08 -07002062 x->km.state = XFRM_STATE_VALID;
2063
2064error:
2065 return err;
2066}
2067
2068EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002069
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002070int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071{
David S. Millerf034b5d2006-08-24 03:08:07 -07002072 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002074 INIT_LIST_HEAD(&net->xfrm.state_all);
2075
David S. Millerf034b5d2006-08-24 03:08:07 -07002076 sz = sizeof(struct hlist_head) * 8;
2077
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002078 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2079 if (!net->xfrm.state_bydst)
2080 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002081 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2082 if (!net->xfrm.state_bysrc)
2083 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002084 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2085 if (!net->xfrm.state_byspi)
2086 goto out_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002087 net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
David S. Millerf034b5d2006-08-24 03:08:07 -07002088
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08002089 net->xfrm.state_num = 0;
Alexey Dobriyan63082732008-11-25 17:19:07 -08002090 INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
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 */