blob: 7ecf6eeff84a3229b25a0cf56140d9398784c7f8 [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
112static unsigned long xfrm_hash_new_size(void)
113{
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800114 return ((init_net.xfrm.state_hmask + 1) << 1) *
David S. Millerf034b5d2006-08-24 03:08:07 -0700115 sizeof(struct hlist_head);
116}
117
118static DEFINE_MUTEX(hash_resize_mutex);
119
David Howellsc4028952006-11-22 14:57:56 +0000120static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700121{
122 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
129 nsize = xfrm_hash_new_size();
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 Dobriyan529983e2008-11-25 17:18:12 -0800148 for (i = init_net.xfrm.state_hmask; i >= 0; i--)
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800149 xfrm_hash_transfer(init_net.xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700150 nhashmask);
151
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800152 odst = init_net.xfrm.state_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800153 osrc = init_net.xfrm.state_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800154 ospi = init_net.xfrm.state_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800155 ohashmask = init_net.xfrm.state_hmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700156
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800157 init_net.xfrm.state_bydst = ndst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800158 init_net.xfrm.state_bysrc = nsrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800159 init_net.xfrm.state_byspi = nspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800160 init_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
David Howellsc4028952006-11-22 14:57:56 +0000173static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175DECLARE_WAIT_QUEUE_HEAD(km_waitq);
176EXPORT_SYMBOL(km_waitq);
177
178static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
179static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
180
181static struct work_struct xfrm_state_gc_work;
Herbert Xu12a169e2008-10-01 07:03:24 -0700182static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static DEFINE_SPINLOCK(xfrm_state_gc_lock);
184
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800185int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800187int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800188void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700190static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
191{
192 struct xfrm_state_afinfo *afinfo;
193 if (unlikely(family >= NPROTO))
194 return NULL;
195 write_lock_bh(&xfrm_state_afinfo_lock);
196 afinfo = xfrm_state_afinfo[family];
197 if (unlikely(!afinfo))
198 write_unlock_bh(&xfrm_state_afinfo_lock);
199 return afinfo;
200}
201
202static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800203 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700204{
205 write_unlock_bh(&xfrm_state_afinfo_lock);
206}
207
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800208int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700209{
210 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800211 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700212 int err = 0;
213
214 if (unlikely(afinfo == NULL))
215 return -EAFNOSUPPORT;
216 typemap = afinfo->type_map;
217
218 if (likely(typemap[type->proto] == NULL))
219 typemap[type->proto] = type;
220 else
221 err = -EEXIST;
222 xfrm_state_unlock_afinfo(afinfo);
223 return err;
224}
225EXPORT_SYMBOL(xfrm_register_type);
226
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800227int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700228{
229 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800230 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700231 int err = 0;
232
233 if (unlikely(afinfo == NULL))
234 return -EAFNOSUPPORT;
235 typemap = afinfo->type_map;
236
237 if (unlikely(typemap[type->proto] != type))
238 err = -ENOENT;
239 else
240 typemap[type->proto] = NULL;
241 xfrm_state_unlock_afinfo(afinfo);
242 return err;
243}
244EXPORT_SYMBOL(xfrm_unregister_type);
245
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800246static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700247{
248 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800249 const struct xfrm_type **typemap;
250 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700251 int modload_attempted = 0;
252
253retry:
254 afinfo = xfrm_state_get_afinfo(family);
255 if (unlikely(afinfo == NULL))
256 return NULL;
257 typemap = afinfo->type_map;
258
259 type = typemap[proto];
260 if (unlikely(type && !try_module_get(type->owner)))
261 type = NULL;
262 if (!type && !modload_attempted) {
263 xfrm_state_put_afinfo(afinfo);
264 request_module("xfrm-type-%d-%d", family, proto);
265 modload_attempted = 1;
266 goto retry;
267 }
268
269 xfrm_state_put_afinfo(afinfo);
270 return type;
271}
272
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800273static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700274{
275 module_put(type->owner);
276}
277
278int xfrm_register_mode(struct xfrm_mode *mode, int family)
279{
280 struct xfrm_state_afinfo *afinfo;
281 struct xfrm_mode **modemap;
282 int err;
283
284 if (unlikely(mode->encap >= XFRM_MODE_MAX))
285 return -EINVAL;
286
287 afinfo = xfrm_state_lock_afinfo(family);
288 if (unlikely(afinfo == NULL))
289 return -EAFNOSUPPORT;
290
291 err = -EEXIST;
292 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700293 if (modemap[mode->encap])
294 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700295
Herbert Xu17c2a422007-10-17 21:33:12 -0700296 err = -ENOENT;
297 if (!try_module_get(afinfo->owner))
298 goto out;
299
300 mode->afinfo = afinfo;
301 modemap[mode->encap] = mode;
302 err = 0;
303
304out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700305 xfrm_state_unlock_afinfo(afinfo);
306 return err;
307}
308EXPORT_SYMBOL(xfrm_register_mode);
309
310int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
311{
312 struct xfrm_state_afinfo *afinfo;
313 struct xfrm_mode **modemap;
314 int err;
315
316 if (unlikely(mode->encap >= XFRM_MODE_MAX))
317 return -EINVAL;
318
319 afinfo = xfrm_state_lock_afinfo(family);
320 if (unlikely(afinfo == NULL))
321 return -EAFNOSUPPORT;
322
323 err = -ENOENT;
324 modemap = afinfo->mode_map;
325 if (likely(modemap[mode->encap] == mode)) {
326 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700327 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700328 err = 0;
329 }
330
331 xfrm_state_unlock_afinfo(afinfo);
332 return err;
333}
334EXPORT_SYMBOL(xfrm_unregister_mode);
335
336static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
337{
338 struct xfrm_state_afinfo *afinfo;
339 struct xfrm_mode *mode;
340 int modload_attempted = 0;
341
342 if (unlikely(encap >= XFRM_MODE_MAX))
343 return NULL;
344
345retry:
346 afinfo = xfrm_state_get_afinfo(family);
347 if (unlikely(afinfo == NULL))
348 return NULL;
349
350 mode = afinfo->mode_map[encap];
351 if (unlikely(mode && !try_module_get(mode->owner)))
352 mode = NULL;
353 if (!mode && !modload_attempted) {
354 xfrm_state_put_afinfo(afinfo);
355 request_module("xfrm-mode-%d-%d", family, encap);
356 modload_attempted = 1;
357 goto retry;
358 }
359
360 xfrm_state_put_afinfo(afinfo);
361 return mode;
362}
363
364static void xfrm_put_mode(struct xfrm_mode *mode)
365{
366 module_put(mode->owner);
367}
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369static void xfrm_state_gc_destroy(struct xfrm_state *x)
370{
David S. Millera47f0ce2006-08-24 03:54:22 -0700371 del_timer_sync(&x->timer);
372 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800373 kfree(x->aalg);
374 kfree(x->ealg);
375 kfree(x->calg);
376 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700377 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700378 if (x->inner_mode)
379 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700380 if (x->inner_mode_iaf)
381 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700382 if (x->outer_mode)
383 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 if (x->type) {
385 x->type->destructor(x);
386 xfrm_put_type(x->type);
387 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800388 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 kfree(x);
390}
391
David Howellsc4028952006-11-22 14:57:56 +0000392static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
Herbert Xu12a169e2008-10-01 07:03:24 -0700394 struct xfrm_state *x;
395 struct hlist_node *entry, *tmp;
396 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700399 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 spin_unlock_bh(&xfrm_state_gc_lock);
401
Herbert Xu12a169e2008-10-01 07:03:24 -0700402 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 wake_up(&km_waitq);
406}
407
408static inline unsigned long make_jiffies(long secs)
409{
410 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
411 return MAX_SCHEDULE_TIMEOUT-1;
412 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900413 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
416static void xfrm_timer_handler(unsigned long data)
417{
418 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800419 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 long next = LONG_MAX;
421 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600422 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 spin_lock(&x->lock);
425 if (x->km.state == XFRM_STATE_DEAD)
426 goto out;
427 if (x->km.state == XFRM_STATE_EXPIRED)
428 goto expired;
429 if (x->lft.hard_add_expires_seconds) {
430 long tmo = x->lft.hard_add_expires_seconds +
431 x->curlft.add_time - now;
432 if (tmo <= 0)
433 goto expired;
434 if (tmo < next)
435 next = tmo;
436 }
437 if (x->lft.hard_use_expires_seconds) {
438 long tmo = x->lft.hard_use_expires_seconds +
439 (x->curlft.use_time ? : now) - now;
440 if (tmo <= 0)
441 goto expired;
442 if (tmo < next)
443 next = tmo;
444 }
445 if (x->km.dying)
446 goto resched;
447 if (x->lft.soft_add_expires_seconds) {
448 long tmo = x->lft.soft_add_expires_seconds +
449 x->curlft.add_time - now;
450 if (tmo <= 0)
451 warn = 1;
452 else if (tmo < next)
453 next = tmo;
454 }
455 if (x->lft.soft_use_expires_seconds) {
456 long tmo = x->lft.soft_use_expires_seconds +
457 (x->curlft.use_time ? : now) - now;
458 if (tmo <= 0)
459 warn = 1;
460 else if (tmo < next)
461 next = tmo;
462 }
463
Herbert Xu4666faa2005-06-18 22:43:22 -0700464 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800466 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700468 if (next != LONG_MAX)
469 mod_timer(&x->timer, jiffies + make_jiffies(next));
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 goto out;
472
473expired:
474 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
475 x->km.state = XFRM_STATE_EXPIRED;
476 wake_up(&km_waitq);
477 next = 2;
478 goto resched;
479 }
Joy Latten161a09e2006-11-27 13:11:54 -0600480
481 err = __xfrm_state_delete(x);
482 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800483 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Joy Lattenab5f5e82007-09-17 11:51:22 -0700485 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400486 audit_get_loginuid(current),
487 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489out:
490 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
David S. Miller0ac84752006-03-20 19:18:23 -0800493static void xfrm_replay_timer_handler(unsigned long data);
494
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800495struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
497 struct xfrm_state *x;
498
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700499 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800502 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 atomic_set(&x->refcnt, 1);
504 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700505 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700506 INIT_HLIST_NODE(&x->bydst);
507 INIT_HLIST_NODE(&x->bysrc);
508 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800509 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
510 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
511 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800512 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 x->lft.soft_byte_limit = XFRM_INF;
514 x->lft.soft_packet_limit = XFRM_INF;
515 x->lft.hard_byte_limit = XFRM_INF;
516 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800517 x->replay_maxage = 0;
518 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700519 x->inner_mode = NULL;
520 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 spin_lock_init(&x->lock);
522 }
523 return x;
524}
525EXPORT_SYMBOL(xfrm_state_alloc);
526
527void __xfrm_state_destroy(struct xfrm_state *x)
528{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700529 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700532 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 spin_unlock_bh(&xfrm_state_gc_lock);
534 schedule_work(&xfrm_state_gc_work);
535}
536EXPORT_SYMBOL(__xfrm_state_destroy);
537
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800538int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700540 int err = -ESRCH;
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (x->km.state != XFRM_STATE_DEAD) {
543 x->km.state = XFRM_STATE_DEAD;
544 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700545 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700546 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700547 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700548 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700549 hlist_del(&x->byspi);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800550 init_net.xfrm.state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 /* All xfrm_state objects are created by xfrm_state_alloc.
554 * The xfrm_state_alloc call gives a reference, and that
555 * is what we are dropping here.
556 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800557 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700558 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700560
561 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800563EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700565int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567 int err;
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700570 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700572
573 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575EXPORT_SYMBOL(xfrm_state_delete);
576
Joy Latten4aa2e622007-06-04 19:05:57 -0400577#ifdef CONFIG_SECURITY_NETWORK_XFRM
578static inline int
579xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Joy Latten4aa2e622007-06-04 19:05:57 -0400581 int i, err = 0;
582
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800583 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400584 struct hlist_node *entry;
585 struct xfrm_state *x;
586
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800587 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400588 if (xfrm_id_proto_match(x->id.proto, proto) &&
589 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700590 xfrm_audit_state_delete(x, 0,
591 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400592 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700593 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400594 return err;
595 }
596 }
597 }
598
599 return err;
600}
601#else
602static inline int
603xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
604{
605 return 0;
606}
607#endif
608
609int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
610{
611 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400614 err = xfrm_state_flush_secctx_check(proto, audit_info);
615 if (err)
616 goto out;
617
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800618 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700619 struct hlist_node *entry;
620 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621restart:
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800622 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700624 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 xfrm_state_hold(x);
626 spin_unlock_bh(&xfrm_state_lock);
627
Joy Latten161a09e2006-11-27 13:11:54 -0600628 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700629 xfrm_audit_state_delete(x, err ? 0 : 1,
630 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400631 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700632 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 xfrm_state_put(x);
634
635 spin_lock_bh(&xfrm_state_lock);
636 goto restart;
637 }
638 }
639 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400640 err = 0;
641
642out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 spin_unlock_bh(&xfrm_state_lock);
644 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400645 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647EXPORT_SYMBOL(xfrm_state_flush);
648
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700649void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700650{
651 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800652 si->sadcnt = init_net.xfrm.state_num;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800653 si->sadhcnt = init_net.xfrm.state_hmask;
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700654 si->sadhmcnt = xfrm_state_hashmax;
655 spin_unlock_bh(&xfrm_state_lock);
656}
657EXPORT_SYMBOL(xfrm_sad_getinfo);
658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659static int
660xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
661 struct xfrm_tmpl *tmpl,
662 xfrm_address_t *daddr, xfrm_address_t *saddr,
663 unsigned short family)
664{
665 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
666 if (!afinfo)
667 return -1;
668 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
669 xfrm_state_put_afinfo(afinfo);
670 return 0;
671}
672
Al Viroa94cfd12006-09-27 18:47:24 -0700673static 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 -0700674{
675 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
676 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700677 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700678
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800679 hlist_for_each_entry(x, entry, init_net.xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700680 if (x->props.family != family ||
681 x->id.spi != spi ||
682 x->id.proto != proto)
683 continue;
684
685 switch (family) {
686 case AF_INET:
687 if (x->id.daddr.a4 != daddr->a4)
688 continue;
689 break;
690 case AF_INET6:
691 if (!ipv6_addr_equal((struct in6_addr *)daddr,
692 (struct in6_addr *)
693 x->id.daddr.a6))
694 continue;
695 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700696 }
David S. Milleredcd5822006-08-24 00:42:45 -0700697
698 xfrm_state_hold(x);
699 return x;
700 }
701
702 return NULL;
703}
704
705static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
706{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700707 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700708 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700709 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700710
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800711 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700712 if (x->props.family != family ||
713 x->id.proto != proto)
714 continue;
715
716 switch (family) {
717 case AF_INET:
718 if (x->id.daddr.a4 != daddr->a4 ||
719 x->props.saddr.a4 != saddr->a4)
720 continue;
721 break;
722 case AF_INET6:
723 if (!ipv6_addr_equal((struct in6_addr *)daddr,
724 (struct in6_addr *)
725 x->id.daddr.a6) ||
726 !ipv6_addr_equal((struct in6_addr *)saddr,
727 (struct in6_addr *)
728 x->props.saddr.a6))
729 continue;
730 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700731 }
David S. Milleredcd5822006-08-24 00:42:45 -0700732
733 xfrm_state_hold(x);
734 return x;
735 }
736
737 return NULL;
738}
739
740static inline struct xfrm_state *
741__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
742{
743 if (use_spi)
744 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
745 x->id.proto, family);
746 else
747 return __xfrm_state_lookup_byaddr(&x->id.daddr,
748 &x->props.saddr,
749 x->id.proto, family);
750}
751
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700752static void xfrm_hash_grow_check(int have_hash_collision)
753{
754 if (have_hash_collision &&
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800755 (init_net.xfrm.state_hmask + 1) < xfrm_state_hashmax &&
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800756 init_net.xfrm.state_num > init_net.xfrm.state_hmask)
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700757 schedule_work(&xfrm_hash_work);
758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900761xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 struct flowi *fl, struct xfrm_tmpl *tmpl,
763 struct xfrm_policy *pol, int *err,
764 unsigned short family)
765{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800766 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700767 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700768 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 int acquire_in_progress = 0;
770 int error = 0;
771 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900772
David S. Miller37b08e32008-09-02 20:14:15 -0700773 to_put = NULL;
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800776 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800777 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (x->props.family == family &&
779 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700780 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 xfrm_state_addr_check(x, daddr, saddr, family) &&
782 tmpl->mode == x->props.mode &&
783 tmpl->id.proto == x->id.proto &&
784 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
785 /* Resolution logic:
786 1. There is a valid state with matching selector.
787 Done.
788 2. Valid state with inappropriate selector. Skip.
789
790 Entering area of "sysdeps".
791
792 3. If state is not valid, selector is temporary,
793 it selects only session which triggered
794 previous resolution. Key manager will do
795 something to install a state with proper
796 selector.
797 */
798 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700799 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700800 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 continue;
802 if (!best ||
803 best->km.dying > x->km.dying ||
804 (best->km.dying == x->km.dying &&
805 best->curlft.add_time < x->curlft.add_time))
806 best = x;
807 } else if (x->km.state == XFRM_STATE_ACQ) {
808 acquire_in_progress = 1;
809 } else if (x->km.state == XFRM_STATE_ERROR ||
810 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700811 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700812 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 error = -ESRCH;
814 }
815 }
816 }
817
818 x = best;
819 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700820 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700821 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
822 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700823 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 error = -EEXIST;
825 goto out;
826 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800827 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (x == NULL) {
829 error = -ENOMEM;
830 goto out;
831 }
832 /* Initialize temporary selector matching only
833 * to current session. */
834 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
835
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700836 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
837 if (error) {
838 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700839 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700840 x = NULL;
841 goto out;
842 }
843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 if (km_query(x, tmpl, pol) == 0) {
845 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800846 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800847 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700848 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800849 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (x->id.spi) {
851 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800852 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
David S. Miller01e67d02007-05-25 00:41:38 -0700854 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
855 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 add_timer(&x->timer);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800857 init_net.xfrm.state_num++;
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700858 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 } else {
860 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700861 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 x = NULL;
863 error = -ESRCH;
864 }
865 }
866out:
867 if (x)
868 xfrm_state_hold(x);
869 else
870 *err = acquire_in_progress ? -EAGAIN : error;
871 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700872 if (to_put)
873 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return x;
875}
876
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700877struct xfrm_state *
878xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
879 unsigned short family, u8 mode, u8 proto, u32 reqid)
880{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800881 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700882 struct xfrm_state *rx = NULL, *x = NULL;
883 struct hlist_node *entry;
884
885 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800886 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800887 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700888 if (x->props.family == family &&
889 x->props.reqid == reqid &&
890 !(x->props.flags & XFRM_STATE_WILDRECV) &&
891 xfrm_state_addr_check(x, daddr, saddr, family) &&
892 mode == x->props.mode &&
893 proto == x->id.proto &&
894 x->km.state == XFRM_STATE_VALID) {
895 rx = x;
896 break;
897 }
898 }
899
900 if (rx)
901 xfrm_state_hold(rx);
902 spin_unlock(&xfrm_state_lock);
903
904
905 return rx;
906}
907EXPORT_SYMBOL(xfrm_stateonly_find);
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909static void __xfrm_state_insert(struct xfrm_state *x)
910{
David S. Millera624c102006-08-24 03:24:33 -0700911 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
David S. Miller9d4a7062006-08-24 03:18:09 -0700913 x->genid = ++xfrm_state_genid;
914
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800915 list_add(&x->km.all, &init_net.xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800916
David S. Millerc1969f22006-08-24 04:00:03 -0700917 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
918 x->props.reqid, x->props.family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800919 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700921 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800922 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700924 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700925 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
926 x->props.family);
927
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800928 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700929 }
930
David S. Millera47f0ce2006-08-24 03:54:22 -0700931 mod_timer(&x->timer, jiffies + HZ);
932 if (x->replay_maxage)
933 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700936
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800937 init_net.xfrm.state_num++;
David S. Millerf034b5d2006-08-24 03:08:07 -0700938
David S. Miller918049f2006-10-12 22:03:24 -0700939 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940}
941
David S. Millerc7f5ea32006-08-24 03:29:04 -0700942/* xfrm_state_lock is held */
943static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
944{
945 unsigned short family = xnew->props.family;
946 u32 reqid = xnew->props.reqid;
947 struct xfrm_state *x;
948 struct hlist_node *entry;
949 unsigned int h;
950
David S. Millerc1969f22006-08-24 04:00:03 -0700951 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800952 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700953 if (x->props.family == family &&
954 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700955 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
956 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700957 x->genid = xfrm_state_genid;
958 }
959}
960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961void xfrm_state_insert(struct xfrm_state *x)
962{
963 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700964 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 __xfrm_state_insert(x);
966 spin_unlock_bh(&xfrm_state_lock);
967}
968EXPORT_SYMBOL(xfrm_state_insert);
969
David S. Miller27708342006-08-24 00:13:10 -0700970/* xfrm_state_lock is held */
971static 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)
972{
David S. Millerc1969f22006-08-24 04:00:03 -0700973 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700974 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700975 struct xfrm_state *x;
976
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800977 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700978 if (x->props.reqid != reqid ||
979 x->props.mode != mode ||
980 x->props.family != family ||
981 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700982 x->id.spi != 0 ||
983 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700984 continue;
985
986 switch (family) {
987 case AF_INET:
988 if (x->id.daddr.a4 != daddr->a4 ||
989 x->props.saddr.a4 != saddr->a4)
990 continue;
991 break;
992 case AF_INET6:
993 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
994 (struct in6_addr *)daddr) ||
995 !ipv6_addr_equal((struct in6_addr *)
996 x->props.saddr.a6,
997 (struct in6_addr *)saddr))
998 continue;
999 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001000 }
David S. Miller27708342006-08-24 00:13:10 -07001001
1002 xfrm_state_hold(x);
1003 return x;
1004 }
1005
1006 if (!create)
1007 return NULL;
1008
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001009 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001010 if (likely(x)) {
1011 switch (family) {
1012 case AF_INET:
1013 x->sel.daddr.a4 = daddr->a4;
1014 x->sel.saddr.a4 = saddr->a4;
1015 x->sel.prefixlen_d = 32;
1016 x->sel.prefixlen_s = 32;
1017 x->props.saddr.a4 = saddr->a4;
1018 x->id.daddr.a4 = daddr->a4;
1019 break;
1020
1021 case AF_INET6:
1022 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1023 (struct in6_addr *)daddr);
1024 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1025 (struct in6_addr *)saddr);
1026 x->sel.prefixlen_d = 128;
1027 x->sel.prefixlen_s = 128;
1028 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1029 (struct in6_addr *)saddr);
1030 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1031 (struct in6_addr *)daddr);
1032 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001033 }
David S. Miller27708342006-08-24 00:13:10 -07001034
1035 x->km.state = XFRM_STATE_ACQ;
1036 x->id.proto = proto;
1037 x->props.family = family;
1038 x->props.mode = mode;
1039 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001040 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001041 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001042 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001043 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001044 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001045 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001046 h = xfrm_src_hash(daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001047 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001048
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08001049 init_net.xfrm.state_num++;
David S. Miller918049f2006-10-12 22:03:24 -07001050
1051 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001052 }
1053
1054 return x;
1055}
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1058
1059int xfrm_state_add(struct xfrm_state *x)
1060{
David S. Miller37b08e32008-09-02 20:14:15 -07001061 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 int family;
1063 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001064 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
David S. Miller37b08e32008-09-02 20:14:15 -07001068 to_put = NULL;
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 spin_lock_bh(&xfrm_state_lock);
1071
David S. Milleredcd5822006-08-24 00:42:45 -07001072 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001074 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 x1 = NULL;
1076 err = -EEXIST;
1077 goto out;
1078 }
1079
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001080 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001082 if (x1 && ((x1->id.proto != x->id.proto) ||
1083 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001084 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 x1 = NULL;
1086 }
1087 }
1088
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001089 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001090 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1091 x->id.proto,
1092 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
David S. Millerc7f5ea32006-08-24 03:29:04 -07001094 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 __xfrm_state_insert(x);
1096 err = 0;
1097
1098out:
1099 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 if (x1) {
1102 xfrm_state_delete(x1);
1103 xfrm_state_put(x1);
1104 }
1105
David S. Miller37b08e32008-09-02 20:14:15 -07001106 if (to_put)
1107 xfrm_state_put(to_put);
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 return err;
1110}
1111EXPORT_SYMBOL(xfrm_state_add);
1112
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001113#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001114static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001115{
1116 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001117 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001118 if (!x)
1119 goto error;
1120
1121 memcpy(&x->id, &orig->id, sizeof(x->id));
1122 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1123 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1124 x->props.mode = orig->props.mode;
1125 x->props.replay_window = orig->props.replay_window;
1126 x->props.reqid = orig->props.reqid;
1127 x->props.family = orig->props.family;
1128 x->props.saddr = orig->props.saddr;
1129
1130 if (orig->aalg) {
1131 x->aalg = xfrm_algo_clone(orig->aalg);
1132 if (!x->aalg)
1133 goto error;
1134 }
1135 x->props.aalgo = orig->props.aalgo;
1136
1137 if (orig->ealg) {
1138 x->ealg = xfrm_algo_clone(orig->ealg);
1139 if (!x->ealg)
1140 goto error;
1141 }
1142 x->props.ealgo = orig->props.ealgo;
1143
1144 if (orig->calg) {
1145 x->calg = xfrm_algo_clone(orig->calg);
1146 if (!x->calg)
1147 goto error;
1148 }
1149 x->props.calgo = orig->props.calgo;
1150
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001151 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001152 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1153 if (!x->encap)
1154 goto error;
1155 }
1156
1157 if (orig->coaddr) {
1158 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1159 GFP_KERNEL);
1160 if (!x->coaddr)
1161 goto error;
1162 }
1163
1164 err = xfrm_init_state(x);
1165 if (err)
1166 goto error;
1167
1168 x->props.flags = orig->props.flags;
1169
1170 x->curlft.add_time = orig->curlft.add_time;
1171 x->km.state = orig->km.state;
1172 x->km.seq = orig->km.seq;
1173
1174 return x;
1175
1176 error:
1177 if (errp)
1178 *errp = err;
1179 if (x) {
1180 kfree(x->aalg);
1181 kfree(x->ealg);
1182 kfree(x->calg);
1183 kfree(x->encap);
1184 kfree(x->coaddr);
1185 }
1186 kfree(x);
1187 return NULL;
1188}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001189
1190/* xfrm_state_lock is held */
1191struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1192{
1193 unsigned int h;
1194 struct xfrm_state *x;
1195 struct hlist_node *entry;
1196
1197 if (m->reqid) {
1198 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1199 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001200 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001201 if (x->props.mode != m->mode ||
1202 x->id.proto != m->proto)
1203 continue;
1204 if (m->reqid && x->props.reqid != m->reqid)
1205 continue;
1206 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1207 m->old_family) ||
1208 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1209 m->old_family))
1210 continue;
1211 xfrm_state_hold(x);
1212 return x;
1213 }
1214 } else {
1215 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1216 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001217 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001218 if (x->props.mode != m->mode ||
1219 x->id.proto != m->proto)
1220 continue;
1221 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1222 m->old_family) ||
1223 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1224 m->old_family))
1225 continue;
1226 xfrm_state_hold(x);
1227 return x;
1228 }
1229 }
1230
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001231 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001232}
1233EXPORT_SYMBOL(xfrm_migrate_state_find);
1234
1235struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1236 struct xfrm_migrate *m)
1237{
1238 struct xfrm_state *xc;
1239 int err;
1240
1241 xc = xfrm_state_clone(x, &err);
1242 if (!xc)
1243 return NULL;
1244
1245 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1246 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1247
1248 /* add state */
1249 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1250 /* a care is needed when the destination address of the
1251 state is to be updated as it is a part of triplet */
1252 xfrm_state_insert(xc);
1253 } else {
1254 if ((err = xfrm_state_add(xc)) < 0)
1255 goto error;
1256 }
1257
1258 return xc;
1259error:
1260 kfree(xc);
1261 return NULL;
1262}
1263EXPORT_SYMBOL(xfrm_state_migrate);
1264#endif
1265
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266int xfrm_state_update(struct xfrm_state *x)
1267{
David S. Miller37b08e32008-09-02 20:14:15 -07001268 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001270 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
David S. Miller37b08e32008-09-02 20:14:15 -07001272 to_put = NULL;
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001275 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
1277 err = -ESRCH;
1278 if (!x1)
1279 goto out;
1280
1281 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001282 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 err = -EEXIST;
1284 goto out;
1285 }
1286
1287 if (x1->km.state == XFRM_STATE_ACQ) {
1288 __xfrm_state_insert(x);
1289 x = NULL;
1290 }
1291 err = 0;
1292
1293out:
1294 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
David S. Miller37b08e32008-09-02 20:14:15 -07001296 if (to_put)
1297 xfrm_state_put(to_put);
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 if (err)
1300 return err;
1301
1302 if (!x) {
1303 xfrm_state_delete(x1);
1304 xfrm_state_put(x1);
1305 return 0;
1306 }
1307
1308 err = -EINVAL;
1309 spin_lock_bh(&x1->lock);
1310 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1311 if (x->encap && x1->encap)
1312 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001313 if (x->coaddr && x1->coaddr) {
1314 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1315 }
1316 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1317 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1319 x1->km.dying = 0;
1320
David S. Millera47f0ce2006-08-24 03:54:22 -07001321 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (x1->curlft.use_time)
1323 xfrm_state_check_expire(x1);
1324
1325 err = 0;
1326 }
1327 spin_unlock_bh(&x1->lock);
1328
1329 xfrm_state_put(x1);
1330
1331 return err;
1332}
1333EXPORT_SYMBOL(xfrm_state_update);
1334
1335int xfrm_state_check_expire(struct xfrm_state *x)
1336{
1337 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001338 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
1340 if (x->km.state != XFRM_STATE_VALID)
1341 return -EINVAL;
1342
1343 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1344 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001345 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001346 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 return -EINVAL;
1348 }
1349
1350 if (!x->km.dying &&
1351 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001352 x->curlft.packets >= x->lft.soft_packet_limit)) {
1353 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001354 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 return 0;
1357}
1358EXPORT_SYMBOL(xfrm_state_check_expire);
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001361xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 unsigned short family)
1363{
1364 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001367 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 return x;
1370}
1371EXPORT_SYMBOL(xfrm_state_lookup);
1372
1373struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001374xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1375 u8 proto, unsigned short family)
1376{
1377 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001378
1379 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001380 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001381 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001382 return x;
1383}
1384EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1385
1386struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001387xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1388 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 int create, unsigned short family)
1390{
1391 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001394 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 return x;
1398}
1399EXPORT_SYMBOL(xfrm_find_acq);
1400
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001401#ifdef CONFIG_XFRM_SUB_POLICY
1402int
1403xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1404 unsigned short family)
1405{
1406 int err = 0;
1407 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1408 if (!afinfo)
1409 return -EAFNOSUPPORT;
1410
1411 spin_lock_bh(&xfrm_state_lock);
1412 if (afinfo->tmpl_sort)
1413 err = afinfo->tmpl_sort(dst, src, n);
1414 spin_unlock_bh(&xfrm_state_lock);
1415 xfrm_state_put_afinfo(afinfo);
1416 return err;
1417}
1418EXPORT_SYMBOL(xfrm_tmpl_sort);
1419
1420int
1421xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1422 unsigned short family)
1423{
1424 int err = 0;
1425 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1426 if (!afinfo)
1427 return -EAFNOSUPPORT;
1428
1429 spin_lock_bh(&xfrm_state_lock);
1430 if (afinfo->state_sort)
1431 err = afinfo->state_sort(dst, src, n);
1432 spin_unlock_bh(&xfrm_state_lock);
1433 xfrm_state_put_afinfo(afinfo);
1434 return err;
1435}
1436EXPORT_SYMBOL(xfrm_state_sort);
1437#endif
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439/* Silly enough, but I'm lazy to build resolution list */
1440
1441static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1442{
1443 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Alexey Dobriyan529983e2008-11-25 17:18:12 -08001445 for (i = 0; i <= init_net.xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001446 struct hlist_node *entry;
1447 struct xfrm_state *x;
1448
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001449 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001450 if (x->km.seq == seq &&
1451 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 xfrm_state_hold(x);
1453 return x;
1454 }
1455 }
1456 }
1457 return NULL;
1458}
1459
1460struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1461{
1462 struct xfrm_state *x;
1463
1464 spin_lock_bh(&xfrm_state_lock);
1465 x = __xfrm_find_acq_byseq(seq);
1466 spin_unlock_bh(&xfrm_state_lock);
1467 return x;
1468}
1469EXPORT_SYMBOL(xfrm_find_acq_byseq);
1470
1471u32 xfrm_get_acqseq(void)
1472{
1473 u32 res;
1474 static u32 acqseq;
1475 static DEFINE_SPINLOCK(acqseq_lock);
1476
1477 spin_lock_bh(&acqseq_lock);
1478 res = (++acqseq ? : ++acqseq);
1479 spin_unlock_bh(&acqseq_lock);
1480 return res;
1481}
1482EXPORT_SYMBOL(xfrm_get_acqseq);
1483
Herbert Xu658b2192007-10-09 13:29:52 -07001484int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485{
David S. Millerf034b5d2006-08-24 03:08:07 -07001486 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001488 int err = -ENOENT;
1489 __be32 minspi = htonl(low);
1490 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Herbert Xu658b2192007-10-09 13:29:52 -07001492 spin_lock_bh(&x->lock);
1493 if (x->km.state == XFRM_STATE_DEAD)
1494 goto unlock;
1495
1496 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001498 goto unlock;
1499
1500 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 if (minspi == maxspi) {
1503 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1504 if (x0) {
1505 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001506 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 }
1508 x->id.spi = minspi;
1509 } else {
1510 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001511 for (h=0; h<high-low+1; h++) {
1512 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1514 if (x0 == NULL) {
1515 x->id.spi = htonl(spi);
1516 break;
1517 }
1518 xfrm_state_put(x0);
1519 }
1520 }
1521 if (x->id.spi) {
1522 spin_lock_bh(&xfrm_state_lock);
1523 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08001524 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001526
1527 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 }
Herbert Xu658b2192007-10-09 13:29:52 -07001529
1530unlock:
1531 spin_unlock_bh(&x->lock);
1532
1533 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534}
1535EXPORT_SYMBOL(xfrm_alloc_spi);
1536
Timo Teras4c563f72008-02-28 21:31:08 -08001537int xfrm_state_walk(struct xfrm_state_walk *walk,
1538 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 void *data)
1540{
Herbert Xu12a169e2008-10-01 07:03:24 -07001541 struct xfrm_state *state;
1542 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 int err = 0;
1544
Herbert Xu12a169e2008-10-01 07:03:24 -07001545 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001546 return 0;
1547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001549 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001550 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001551 else
1552 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001553 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001554 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001555 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001556 state = container_of(x, struct xfrm_state, km);
1557 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001558 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001559 err = func(state, walk->seq, data);
1560 if (err) {
1561 list_move_tail(&walk->all, &x->all);
1562 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001564 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001566 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 err = -ENOENT;
1568 goto out;
1569 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001570 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571out:
1572 spin_unlock_bh(&xfrm_state_lock);
1573 return err;
1574}
1575EXPORT_SYMBOL(xfrm_state_walk);
1576
Herbert Xu5c182452008-09-22 19:48:19 -07001577void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1578{
Herbert Xu12a169e2008-10-01 07:03:24 -07001579 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001580 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001581 walk->state = XFRM_STATE_DEAD;
1582 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001583}
1584EXPORT_SYMBOL(xfrm_state_walk_init);
1585
Herbert Xuabb81c42008-09-09 19:58:29 -07001586void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1587{
Herbert Xu12a169e2008-10-01 07:03:24 -07001588 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001589 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001590
Herbert Xu12a169e2008-10-01 07:03:24 -07001591 spin_lock_bh(&xfrm_state_lock);
1592 list_del(&walk->all);
1593 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001594}
1595EXPORT_SYMBOL(xfrm_state_walk_done);
1596
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001597
1598void xfrm_replay_notify(struct xfrm_state *x, int event)
1599{
1600 struct km_event c;
1601 /* we send notify messages in case
1602 * 1. we updated on of the sequence numbers, and the seqno difference
1603 * is at least x->replay_maxdiff, in this case we also update the
1604 * timeout of our timer function
1605 * 2. if x->replay_maxage has elapsed since last update,
1606 * and there were changes
1607 *
1608 * The state structure must be locked!
1609 */
1610
1611 switch (event) {
1612 case XFRM_REPLAY_UPDATE:
1613 if (x->replay_maxdiff &&
1614 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001615 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1616 if (x->xflags & XFRM_TIME_DEFER)
1617 event = XFRM_REPLAY_TIMEOUT;
1618 else
1619 return;
1620 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001621
1622 break;
1623
1624 case XFRM_REPLAY_TIMEOUT:
1625 if ((x->replay.seq == x->preplay.seq) &&
1626 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001627 (x->replay.oseq == x->preplay.oseq)) {
1628 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001629 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001630 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001631
1632 break;
1633 }
1634
1635 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1636 c.event = XFRM_MSG_NEWAE;
1637 c.data.aevent = event;
1638 km_state_notify(x, &c);
1639
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001640 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001641 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001642 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001643}
1644
1645static void xfrm_replay_timer_handler(unsigned long data)
1646{
1647 struct xfrm_state *x = (struct xfrm_state*)data;
1648
1649 spin_lock(&x->lock);
1650
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001651 if (x->km.state == XFRM_STATE_VALID) {
1652 if (xfrm_aevent_is_on())
1653 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1654 else
1655 x->xflags |= XFRM_TIME_DEFER;
1656 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001657
1658 spin_unlock(&x->lock);
1659}
1660
Paul Mooreafeb14b2007-12-21 14:58:11 -08001661int xfrm_replay_check(struct xfrm_state *x,
1662 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663{
1664 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001665 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001668 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 if (likely(seq > x->replay.seq))
1671 return 0;
1672
1673 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001674 if (diff >= min_t(unsigned int, x->props.replay_window,
1675 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001677 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 }
1679
1680 if (x->replay.bitmap & (1U << diff)) {
1681 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001682 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 }
1684 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001685
1686err:
1687 xfrm_audit_state_replay(x, skb, net_seq);
1688 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Al Viro61f46272006-09-27 18:48:33 -07001691void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
1693 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001694 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 if (seq > x->replay.seq) {
1697 diff = seq - x->replay.seq;
1698 if (diff < x->props.replay_window)
1699 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1700 else
1701 x->replay.bitmap = 1;
1702 x->replay.seq = seq;
1703 } else {
1704 diff = x->replay.seq - seq;
1705 x->replay.bitmap |= (1U << diff);
1706 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001707
1708 if (xfrm_aevent_is_on())
1709 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
Denis Chengdf018122007-12-07 00:51:11 -08001712static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713static DEFINE_RWLOCK(xfrm_km_lock);
1714
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001715void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716{
1717 struct xfrm_mgr *km;
1718
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001719 read_lock(&xfrm_km_lock);
1720 list_for_each_entry(km, &xfrm_km_list, list)
1721 if (km->notify_policy)
1722 km->notify_policy(xp, dir, c);
1723 read_unlock(&xfrm_km_lock);
1724}
1725
1726void km_state_notify(struct xfrm_state *x, struct km_event *c)
1727{
1728 struct xfrm_mgr *km;
1729 read_lock(&xfrm_km_lock);
1730 list_for_each_entry(km, &xfrm_km_list, list)
1731 if (km->notify)
1732 km->notify(x, c);
1733 read_unlock(&xfrm_km_lock);
1734}
1735
1736EXPORT_SYMBOL(km_policy_notify);
1737EXPORT_SYMBOL(km_state_notify);
1738
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001739void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001740{
1741 struct km_event c;
1742
Herbert Xubf088672005-06-18 22:44:00 -07001743 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001744 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001745 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001746 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
1748 if (hard)
1749 wake_up(&km_waitq);
1750}
1751
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001752EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001753/*
1754 * We send to all registered managers regardless of failure
1755 * We are happy with one success
1756*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001757int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001759 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 struct xfrm_mgr *km;
1761
1762 read_lock(&xfrm_km_lock);
1763 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001764 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1765 if (!acqret)
1766 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 }
1768 read_unlock(&xfrm_km_lock);
1769 return err;
1770}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001771EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
Al Viro5d36b182006-11-08 00:24:06 -08001773int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774{
1775 int err = -EINVAL;
1776 struct xfrm_mgr *km;
1777
1778 read_lock(&xfrm_km_lock);
1779 list_for_each_entry(km, &xfrm_km_list, list) {
1780 if (km->new_mapping)
1781 err = km->new_mapping(x, ipaddr, sport);
1782 if (!err)
1783 break;
1784 }
1785 read_unlock(&xfrm_km_lock);
1786 return err;
1787}
1788EXPORT_SYMBOL(km_new_mapping);
1789
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001790void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001792 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Herbert Xubf088672005-06-18 22:44:00 -07001794 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001795 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001796 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001797 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
1799 if (hard)
1800 wake_up(&km_waitq);
1801}
David S. Millera70fcb02006-03-20 19:18:52 -08001802EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001804#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001805int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001806 struct xfrm_migrate *m, int num_migrate,
1807 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001808{
1809 int err = -EINVAL;
1810 int ret;
1811 struct xfrm_mgr *km;
1812
1813 read_lock(&xfrm_km_lock);
1814 list_for_each_entry(km, &xfrm_km_list, list) {
1815 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001816 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001817 if (!ret)
1818 err = ret;
1819 }
1820 }
1821 read_unlock(&xfrm_km_lock);
1822 return err;
1823}
1824EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001825#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001826
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001827int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1828{
1829 int err = -EINVAL;
1830 int ret;
1831 struct xfrm_mgr *km;
1832
1833 read_lock(&xfrm_km_lock);
1834 list_for_each_entry(km, &xfrm_km_list, list) {
1835 if (km->report) {
1836 ret = km->report(proto, sel, addr);
1837 if (!ret)
1838 err = ret;
1839 }
1840 }
1841 read_unlock(&xfrm_km_lock);
1842 return err;
1843}
1844EXPORT_SYMBOL(km_report);
1845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1847{
1848 int err;
1849 u8 *data;
1850 struct xfrm_mgr *km;
1851 struct xfrm_policy *pol = NULL;
1852
1853 if (optlen <= 0 || optlen > PAGE_SIZE)
1854 return -EMSGSIZE;
1855
1856 data = kmalloc(optlen, GFP_KERNEL);
1857 if (!data)
1858 return -ENOMEM;
1859
1860 err = -EFAULT;
1861 if (copy_from_user(data, optval, optlen))
1862 goto out;
1863
1864 err = -EINVAL;
1865 read_lock(&xfrm_km_lock);
1866 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001867 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 optlen, &err);
1869 if (err >= 0)
1870 break;
1871 }
1872 read_unlock(&xfrm_km_lock);
1873
1874 if (err >= 0) {
1875 xfrm_sk_policy_insert(sk, err, pol);
1876 xfrm_pol_put(pol);
1877 err = 0;
1878 }
1879
1880out:
1881 kfree(data);
1882 return err;
1883}
1884EXPORT_SYMBOL(xfrm_user_policy);
1885
1886int xfrm_register_km(struct xfrm_mgr *km)
1887{
1888 write_lock_bh(&xfrm_km_lock);
1889 list_add_tail(&km->list, &xfrm_km_list);
1890 write_unlock_bh(&xfrm_km_lock);
1891 return 0;
1892}
1893EXPORT_SYMBOL(xfrm_register_km);
1894
1895int xfrm_unregister_km(struct xfrm_mgr *km)
1896{
1897 write_lock_bh(&xfrm_km_lock);
1898 list_del(&km->list);
1899 write_unlock_bh(&xfrm_km_lock);
1900 return 0;
1901}
1902EXPORT_SYMBOL(xfrm_unregister_km);
1903
1904int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1905{
1906 int err = 0;
1907 if (unlikely(afinfo == NULL))
1908 return -EINVAL;
1909 if (unlikely(afinfo->family >= NPROTO))
1910 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001911 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1913 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001914 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001916 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 return err;
1918}
1919EXPORT_SYMBOL(xfrm_state_register_afinfo);
1920
1921int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1922{
1923 int err = 0;
1924 if (unlikely(afinfo == NULL))
1925 return -EINVAL;
1926 if (unlikely(afinfo->family >= NPROTO))
1927 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001928 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1930 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1931 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001932 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001935 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 return err;
1937}
1938EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1939
Herbert Xu17c2a422007-10-17 21:33:12 -07001940static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941{
1942 struct xfrm_state_afinfo *afinfo;
1943 if (unlikely(family >= NPROTO))
1944 return NULL;
1945 read_lock(&xfrm_state_afinfo_lock);
1946 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001947 if (unlikely(!afinfo))
1948 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return afinfo;
1950}
1951
Herbert Xu17c2a422007-10-17 21:33:12 -07001952static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001953 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954{
Herbert Xu546be242006-05-27 23:03:58 -07001955 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956}
1957
1958/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1959void xfrm_state_delete_tunnel(struct xfrm_state *x)
1960{
1961 if (x->tunnel) {
1962 struct xfrm_state *t = x->tunnel;
1963
1964 if (atomic_read(&t->tunnel_users) == 2)
1965 xfrm_state_delete(t);
1966 atomic_dec(&t->tunnel_users);
1967 xfrm_state_put(t);
1968 x->tunnel = NULL;
1969 }
1970}
1971EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1972
1973int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1974{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001975 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Patrick McHardyc5c25232007-04-09 11:47:18 -07001977 spin_lock_bh(&x->lock);
1978 if (x->km.state == XFRM_STATE_VALID &&
1979 x->type && x->type->get_mtu)
1980 res = x->type->get_mtu(x, mtu);
1981 else
Patrick McHardy28121612007-06-18 22:30:15 -07001982 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001983 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 return res;
1985}
1986
Herbert Xu72cb6962005-06-20 13:18:08 -07001987int xfrm_init_state(struct xfrm_state *x)
1988{
Herbert Xud094cd82005-06-20 13:19:41 -07001989 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001990 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07001991 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07001992 int err;
1993
Herbert Xud094cd82005-06-20 13:19:41 -07001994 err = -EAFNOSUPPORT;
1995 afinfo = xfrm_state_get_afinfo(family);
1996 if (!afinfo)
1997 goto error;
1998
1999 err = 0;
2000 if (afinfo->init_flags)
2001 err = afinfo->init_flags(x);
2002
2003 xfrm_state_put_afinfo(afinfo);
2004
2005 if (err)
2006 goto error;
2007
2008 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002009
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002010 if (x->sel.family != AF_UNSPEC) {
2011 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2012 if (inner_mode == NULL)
2013 goto error;
2014
2015 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2016 family != x->sel.family) {
2017 xfrm_put_mode(inner_mode);
2018 goto error;
2019 }
2020
2021 x->inner_mode = inner_mode;
2022 } else {
2023 struct xfrm_mode *inner_mode_iaf;
2024
2025 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2026 if (inner_mode == NULL)
2027 goto error;
2028
2029 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2030 xfrm_put_mode(inner_mode);
2031 goto error;
2032 }
2033
2034 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2035 if (inner_mode_iaf == NULL)
2036 goto error;
2037
2038 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2039 xfrm_put_mode(inner_mode_iaf);
2040 goto error;
2041 }
2042
2043 if (x->props.family == AF_INET) {
2044 x->inner_mode = inner_mode;
2045 x->inner_mode_iaf = inner_mode_iaf;
2046 } else {
2047 x->inner_mode = inner_mode_iaf;
2048 x->inner_mode_iaf = inner_mode;
2049 }
2050 }
Herbert Xu13996372007-10-17 21:35:51 -07002051
Herbert Xud094cd82005-06-20 13:19:41 -07002052 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002053 if (x->type == NULL)
2054 goto error;
2055
2056 err = x->type->init_state(x);
2057 if (err)
2058 goto error;
2059
Herbert Xu13996372007-10-17 21:35:51 -07002060 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2061 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002062 goto error;
2063
Herbert Xu72cb6962005-06-20 13:18:08 -07002064 x->km.state = XFRM_STATE_VALID;
2065
2066error:
2067 return err;
2068}
2069
2070EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002071
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002072int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073{
David S. Millerf034b5d2006-08-24 03:08:07 -07002074 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002076 INIT_LIST_HEAD(&net->xfrm.state_all);
2077
David S. Millerf034b5d2006-08-24 03:08:07 -07002078 sz = sizeof(struct hlist_head) * 8;
2079
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002080 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2081 if (!net->xfrm.state_bydst)
2082 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002083 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2084 if (!net->xfrm.state_bysrc)
2085 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002086 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2087 if (!net->xfrm.state_byspi)
2088 goto out_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002089 net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
David S. Millerf034b5d2006-08-24 03:08:07 -07002090
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08002091 net->xfrm.state_num = 0;
David Howellsc4028952006-11-22 14:57:56 +00002092 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002093 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002094
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002095out_byspi:
2096 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002097out_bysrc:
2098 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002099out_bydst:
2100 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002101}
2102
2103void xfrm_state_fini(struct net *net)
2104{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002105 unsigned int sz;
2106
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002107 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002108
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002109 sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002110 WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2111 xfrm_hash_free(net->xfrm.state_byspi, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002112 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2113 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002114 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2115 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116}
2117
Joy Lattenab5f5e82007-09-17 11:51:22 -07002118#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002119static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2120 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002121{
Paul Moore68277ac2007-12-20 20:49:33 -08002122 struct xfrm_sec_ctx *ctx = x->security;
2123 u32 spi = ntohl(x->id.spi);
2124
2125 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002126 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002127 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002128
2129 switch(x->props.family) {
2130 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002131 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2132 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002133 break;
2134 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002135 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002136 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002137 break;
2138 }
Paul Moore68277ac2007-12-20 20:49:33 -08002139
2140 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002141}
2142
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002143static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2144 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002145{
2146 struct iphdr *iph4;
2147 struct ipv6hdr *iph6;
2148
2149 switch (family) {
2150 case AF_INET:
2151 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002152 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2153 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002154 break;
2155 case AF_INET6:
2156 iph6 = ipv6_hdr(skb);
2157 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002158 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002159 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002160 iph6->flow_lbl[0] & 0x0f,
2161 iph6->flow_lbl[1],
2162 iph6->flow_lbl[2]);
2163 break;
2164 }
2165}
2166
Paul Moore68277ac2007-12-20 20:49:33 -08002167void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002168 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002169{
2170 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002171
Paul Mooreafeb14b2007-12-21 14:58:11 -08002172 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002173 if (audit_buf == NULL)
2174 return;
Eric Paris25323862008-04-18 10:09:25 -04002175 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002176 xfrm_audit_helper_sainfo(x, audit_buf);
2177 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002178 audit_log_end(audit_buf);
2179}
2180EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2181
Paul Moore68277ac2007-12-20 20:49:33 -08002182void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002183 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002184{
2185 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002186
Paul Mooreafeb14b2007-12-21 14:58:11 -08002187 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002188 if (audit_buf == NULL)
2189 return;
Eric Paris25323862008-04-18 10:09:25 -04002190 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002191 xfrm_audit_helper_sainfo(x, audit_buf);
2192 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002193 audit_log_end(audit_buf);
2194}
2195EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002196
2197void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2198 struct sk_buff *skb)
2199{
2200 struct audit_buffer *audit_buf;
2201 u32 spi;
2202
2203 audit_buf = xfrm_audit_start("SA-replay-overflow");
2204 if (audit_buf == NULL)
2205 return;
2206 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2207 /* don't record the sequence number because it's inherent in this kind
2208 * of audit message */
2209 spi = ntohl(x->id.spi);
2210 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2211 audit_log_end(audit_buf);
2212}
2213EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2214
2215static void xfrm_audit_state_replay(struct xfrm_state *x,
2216 struct sk_buff *skb, __be32 net_seq)
2217{
2218 struct audit_buffer *audit_buf;
2219 u32 spi;
2220
2221 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2222 if (audit_buf == NULL)
2223 return;
2224 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2225 spi = ntohl(x->id.spi);
2226 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2227 spi, spi, ntohl(net_seq));
2228 audit_log_end(audit_buf);
2229}
2230
2231void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2232{
2233 struct audit_buffer *audit_buf;
2234
2235 audit_buf = xfrm_audit_start("SA-notfound");
2236 if (audit_buf == NULL)
2237 return;
2238 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2239 audit_log_end(audit_buf);
2240}
2241EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2242
2243void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2244 __be32 net_spi, __be32 net_seq)
2245{
2246 struct audit_buffer *audit_buf;
2247 u32 spi;
2248
2249 audit_buf = xfrm_audit_start("SA-notfound");
2250 if (audit_buf == NULL)
2251 return;
2252 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2253 spi = ntohl(net_spi);
2254 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2255 spi, spi, ntohl(net_seq));
2256 audit_log_end(audit_buf);
2257}
2258EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2259
2260void xfrm_audit_state_icvfail(struct xfrm_state *x,
2261 struct sk_buff *skb, u8 proto)
2262{
2263 struct audit_buffer *audit_buf;
2264 __be32 net_spi;
2265 __be32 net_seq;
2266
2267 audit_buf = xfrm_audit_start("SA-icv-failure");
2268 if (audit_buf == NULL)
2269 return;
2270 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2271 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2272 u32 spi = ntohl(net_spi);
2273 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2274 spi, spi, ntohl(net_seq));
2275 }
2276 audit_log_end(audit_buf);
2277}
2278EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002279#endif /* CONFIG_AUDITSYSCALL */