blob: d594b5af5f6b1bece8d1b81e79350faf372cf133 [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. Miller01e67d02007-05-25 00:41:38 -070027u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME;
David S. Millera70fcb02006-03-20 19:18:52 -080028EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
29
David S. Miller01e67d02007-05-25 00:41:38 -070030u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE;
David S. Millera70fcb02006-03-20 19:18:52 -080031EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
32
David S. Miller01e67d02007-05-25 00:41:38 -070033u32 sysctl_xfrm_acq_expires __read_mostly = 30;
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* Each xfrm_state may be linked to two tables:
36
37 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
David S. Millera624c102006-08-24 03:24:33 -070038 2. Hash table by (daddr,family,reqid) to find what SAs exist for given
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 destination/tunnel endpoint. (output)
40 */
41
42static DEFINE_SPINLOCK(xfrm_state_lock);
43
David S. Millerf034b5d2006-08-24 03:08:07 -070044static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
David S. Miller9d4a7062006-08-24 03:18:09 -070045static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Herbert Xu17c2a422007-10-17 21:33:12 -070047static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
48static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
49
Paul Mooreafeb14b2007-12-21 14:58:11 -080050#ifdef CONFIG_AUDITSYSCALL
51static void xfrm_audit_state_replay(struct xfrm_state *x,
52 struct sk_buff *skb, __be32 net_seq);
53#else
54#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
55#endif /* CONFIG_AUDITSYSCALL */
56
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080057static inline unsigned int xfrm_dst_hash(struct net *net,
58 xfrm_address_t *daddr,
David S. Millerc1969f22006-08-24 04:00:03 -070059 xfrm_address_t *saddr,
60 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070061 unsigned short family)
62{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080063 return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070064}
65
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080066static inline unsigned int xfrm_src_hash(struct net *net,
67 xfrm_address_t *daddr,
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070068 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070069 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070070{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080071 return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070072}
73
David S. Miller2575b652006-08-24 03:26:44 -070074static inline unsigned int
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080075xfrm_spi_hash(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070076{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080077 return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070078}
79
David S. Millerf034b5d2006-08-24 03:08:07 -070080static void xfrm_hash_transfer(struct hlist_head *list,
81 struct hlist_head *ndsttable,
82 struct hlist_head *nsrctable,
83 struct hlist_head *nspitable,
84 unsigned int nhashmask)
85{
86 struct hlist_node *entry, *tmp;
87 struct xfrm_state *x;
88
89 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
90 unsigned int h;
91
David S. Millerc1969f22006-08-24 04:00:03 -070092 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
93 x->props.reqid, x->props.family,
94 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070095 hlist_add_head(&x->bydst, ndsttable+h);
96
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070097 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
98 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -070099 nhashmask);
100 hlist_add_head(&x->bysrc, nsrctable+h);
101
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700102 if (x->id.spi) {
103 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
104 x->id.proto, x->props.family,
105 nhashmask);
106 hlist_add_head(&x->byspi, nspitable+h);
107 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700108 }
109}
110
Alexey Dobriyan63082732008-11-25 17:19:07 -0800111static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
David S. Millerf034b5d2006-08-24 03:08:07 -0700112{
Alexey Dobriyan63082732008-11-25 17:19:07 -0800113 return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
David S. Millerf034b5d2006-08-24 03:08:07 -0700114}
115
116static DEFINE_MUTEX(hash_resize_mutex);
117
Alexey Dobriyan63082732008-11-25 17:19:07 -0800118static void xfrm_hash_resize(struct work_struct *work)
David S. Millerf034b5d2006-08-24 03:08:07 -0700119{
Alexey Dobriyan63082732008-11-25 17:19:07 -0800120 struct net *net = container_of(work, struct net, xfrm.state_hash_work);
David S. Millerf034b5d2006-08-24 03:08:07 -0700121 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
122 unsigned long nsize, osize;
123 unsigned int nhashmask, ohashmask;
124 int i;
125
126 mutex_lock(&hash_resize_mutex);
127
Alexey Dobriyan63082732008-11-25 17:19:07 -0800128 nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
David S. Miller44e36b42006-08-24 04:50:50 -0700129 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700130 if (!ndst)
131 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700132 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700133 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700134 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700135 goto out_unlock;
136 }
David S. Miller44e36b42006-08-24 04:50:50 -0700137 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700138 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700139 xfrm_hash_free(ndst, nsize);
140 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700141 goto out_unlock;
142 }
143
144 spin_lock_bh(&xfrm_state_lock);
145
146 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
Alexey Dobriyan63082732008-11-25 17:19:07 -0800147 for (i = net->xfrm.state_hmask; i >= 0; i--)
148 xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700149 nhashmask);
150
Alexey Dobriyan63082732008-11-25 17:19:07 -0800151 odst = net->xfrm.state_bydst;
152 osrc = net->xfrm.state_bysrc;
153 ospi = net->xfrm.state_byspi;
154 ohashmask = net->xfrm.state_hmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700155
Alexey Dobriyan63082732008-11-25 17:19:07 -0800156 net->xfrm.state_bydst = ndst;
157 net->xfrm.state_bysrc = nsrc;
158 net->xfrm.state_byspi = nspi;
159 net->xfrm.state_hmask = nhashmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700160
161 spin_unlock_bh(&xfrm_state_lock);
162
163 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700164 xfrm_hash_free(odst, osize);
165 xfrm_hash_free(osrc, osize);
166 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700167
168out_unlock:
169 mutex_unlock(&hash_resize_mutex);
170}
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
173static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static DEFINE_SPINLOCK(xfrm_state_gc_lock);
176
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800177int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800179int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800180void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700182static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
183{
184 struct xfrm_state_afinfo *afinfo;
185 if (unlikely(family >= NPROTO))
186 return NULL;
187 write_lock_bh(&xfrm_state_afinfo_lock);
188 afinfo = xfrm_state_afinfo[family];
189 if (unlikely(!afinfo))
190 write_unlock_bh(&xfrm_state_afinfo_lock);
191 return afinfo;
192}
193
194static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800195 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700196{
197 write_unlock_bh(&xfrm_state_afinfo_lock);
198}
199
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800200int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700201{
202 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800203 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700204 int err = 0;
205
206 if (unlikely(afinfo == NULL))
207 return -EAFNOSUPPORT;
208 typemap = afinfo->type_map;
209
210 if (likely(typemap[type->proto] == NULL))
211 typemap[type->proto] = type;
212 else
213 err = -EEXIST;
214 xfrm_state_unlock_afinfo(afinfo);
215 return err;
216}
217EXPORT_SYMBOL(xfrm_register_type);
218
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800219int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700220{
221 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800222 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700223 int err = 0;
224
225 if (unlikely(afinfo == NULL))
226 return -EAFNOSUPPORT;
227 typemap = afinfo->type_map;
228
229 if (unlikely(typemap[type->proto] != type))
230 err = -ENOENT;
231 else
232 typemap[type->proto] = NULL;
233 xfrm_state_unlock_afinfo(afinfo);
234 return err;
235}
236EXPORT_SYMBOL(xfrm_unregister_type);
237
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800238static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700239{
240 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800241 const struct xfrm_type **typemap;
242 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700243 int modload_attempted = 0;
244
245retry:
246 afinfo = xfrm_state_get_afinfo(family);
247 if (unlikely(afinfo == NULL))
248 return NULL;
249 typemap = afinfo->type_map;
250
251 type = typemap[proto];
252 if (unlikely(type && !try_module_get(type->owner)))
253 type = NULL;
254 if (!type && !modload_attempted) {
255 xfrm_state_put_afinfo(afinfo);
256 request_module("xfrm-type-%d-%d", family, proto);
257 modload_attempted = 1;
258 goto retry;
259 }
260
261 xfrm_state_put_afinfo(afinfo);
262 return type;
263}
264
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800265static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700266{
267 module_put(type->owner);
268}
269
270int xfrm_register_mode(struct xfrm_mode *mode, int family)
271{
272 struct xfrm_state_afinfo *afinfo;
273 struct xfrm_mode **modemap;
274 int err;
275
276 if (unlikely(mode->encap >= XFRM_MODE_MAX))
277 return -EINVAL;
278
279 afinfo = xfrm_state_lock_afinfo(family);
280 if (unlikely(afinfo == NULL))
281 return -EAFNOSUPPORT;
282
283 err = -EEXIST;
284 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700285 if (modemap[mode->encap])
286 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700287
Herbert Xu17c2a422007-10-17 21:33:12 -0700288 err = -ENOENT;
289 if (!try_module_get(afinfo->owner))
290 goto out;
291
292 mode->afinfo = afinfo;
293 modemap[mode->encap] = mode;
294 err = 0;
295
296out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700297 xfrm_state_unlock_afinfo(afinfo);
298 return err;
299}
300EXPORT_SYMBOL(xfrm_register_mode);
301
302int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
303{
304 struct xfrm_state_afinfo *afinfo;
305 struct xfrm_mode **modemap;
306 int err;
307
308 if (unlikely(mode->encap >= XFRM_MODE_MAX))
309 return -EINVAL;
310
311 afinfo = xfrm_state_lock_afinfo(family);
312 if (unlikely(afinfo == NULL))
313 return -EAFNOSUPPORT;
314
315 err = -ENOENT;
316 modemap = afinfo->mode_map;
317 if (likely(modemap[mode->encap] == mode)) {
318 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700319 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700320 err = 0;
321 }
322
323 xfrm_state_unlock_afinfo(afinfo);
324 return err;
325}
326EXPORT_SYMBOL(xfrm_unregister_mode);
327
328static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
329{
330 struct xfrm_state_afinfo *afinfo;
331 struct xfrm_mode *mode;
332 int modload_attempted = 0;
333
334 if (unlikely(encap >= XFRM_MODE_MAX))
335 return NULL;
336
337retry:
338 afinfo = xfrm_state_get_afinfo(family);
339 if (unlikely(afinfo == NULL))
340 return NULL;
341
342 mode = afinfo->mode_map[encap];
343 if (unlikely(mode && !try_module_get(mode->owner)))
344 mode = NULL;
345 if (!mode && !modload_attempted) {
346 xfrm_state_put_afinfo(afinfo);
347 request_module("xfrm-mode-%d-%d", family, encap);
348 modload_attempted = 1;
349 goto retry;
350 }
351
352 xfrm_state_put_afinfo(afinfo);
353 return mode;
354}
355
356static void xfrm_put_mode(struct xfrm_mode *mode)
357{
358 module_put(mode->owner);
359}
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361static void xfrm_state_gc_destroy(struct xfrm_state *x)
362{
David S. Millera47f0ce2006-08-24 03:54:22 -0700363 del_timer_sync(&x->timer);
364 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800365 kfree(x->aalg);
366 kfree(x->ealg);
367 kfree(x->calg);
368 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700369 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700370 if (x->inner_mode)
371 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700372 if (x->inner_mode_iaf)
373 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700374 if (x->outer_mode)
375 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (x->type) {
377 x->type->destructor(x);
378 xfrm_put_type(x->type);
379 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800380 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 kfree(x);
382}
383
Alexey Dobriyanc7837142008-11-25 17:20:36 -0800384static void xfrm_state_gc_task(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
Alexey Dobriyanc7837142008-11-25 17:20:36 -0800386 struct net *net = container_of(work, struct net, xfrm.state_gc_work);
Herbert Xu12a169e2008-10-01 07:03:24 -0700387 struct xfrm_state *x;
388 struct hlist_node *entry, *tmp;
389 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 spin_lock_bh(&xfrm_state_gc_lock);
Alexey Dobriyanc7837142008-11-25 17:20:36 -0800392 hlist_move_list(&net->xfrm.state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 spin_unlock_bh(&xfrm_state_gc_lock);
394
Herbert Xu12a169e2008-10-01 07:03:24 -0700395 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700397
Alexey Dobriyan50a30652008-11-25 17:21:01 -0800398 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
401static inline unsigned long make_jiffies(long secs)
402{
403 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
404 return MAX_SCHEDULE_TIMEOUT-1;
405 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900406 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407}
408
409static void xfrm_timer_handler(unsigned long data)
410{
411 struct xfrm_state *x = (struct xfrm_state*)data;
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800412 struct net *net = xs_net(x);
James Morris9d729f72007-03-04 16:12:44 -0800413 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 long next = LONG_MAX;
415 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600416 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 spin_lock(&x->lock);
419 if (x->km.state == XFRM_STATE_DEAD)
420 goto out;
421 if (x->km.state == XFRM_STATE_EXPIRED)
422 goto expired;
423 if (x->lft.hard_add_expires_seconds) {
424 long tmo = x->lft.hard_add_expires_seconds +
425 x->curlft.add_time - now;
426 if (tmo <= 0)
427 goto expired;
428 if (tmo < next)
429 next = tmo;
430 }
431 if (x->lft.hard_use_expires_seconds) {
432 long tmo = x->lft.hard_use_expires_seconds +
433 (x->curlft.use_time ? : now) - now;
434 if (tmo <= 0)
435 goto expired;
436 if (tmo < next)
437 next = tmo;
438 }
439 if (x->km.dying)
440 goto resched;
441 if (x->lft.soft_add_expires_seconds) {
442 long tmo = x->lft.soft_add_expires_seconds +
443 x->curlft.add_time - now;
444 if (tmo <= 0)
445 warn = 1;
446 else if (tmo < next)
447 next = tmo;
448 }
449 if (x->lft.soft_use_expires_seconds) {
450 long tmo = x->lft.soft_use_expires_seconds +
451 (x->curlft.use_time ? : now) - now;
452 if (tmo <= 0)
453 warn = 1;
454 else if (tmo < next)
455 next = tmo;
456 }
457
Herbert Xu4666faa2005-06-18 22:43:22 -0700458 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800460 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700462 if (next != LONG_MAX)
463 mod_timer(&x->timer, jiffies + make_jiffies(next));
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 goto out;
466
467expired:
468 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
469 x->km.state = XFRM_STATE_EXPIRED;
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800470 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 next = 2;
472 goto resched;
473 }
Joy Latten161a09e2006-11-27 13:11:54 -0600474
475 err = __xfrm_state_delete(x);
476 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800477 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Joy Lattenab5f5e82007-09-17 11:51:22 -0700479 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400480 audit_get_loginuid(current),
481 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483out:
484 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
David S. Miller0ac84752006-03-20 19:18:23 -0800487static void xfrm_replay_timer_handler(unsigned long data);
488
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800489struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
491 struct xfrm_state *x;
492
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700493 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800496 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 atomic_set(&x->refcnt, 1);
498 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700499 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700500 INIT_HLIST_NODE(&x->bydst);
501 INIT_HLIST_NODE(&x->bysrc);
502 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800503 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
504 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
505 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800506 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 x->lft.soft_byte_limit = XFRM_INF;
508 x->lft.soft_packet_limit = XFRM_INF;
509 x->lft.hard_byte_limit = XFRM_INF;
510 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800511 x->replay_maxage = 0;
512 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700513 x->inner_mode = NULL;
514 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 spin_lock_init(&x->lock);
516 }
517 return x;
518}
519EXPORT_SYMBOL(xfrm_state_alloc);
520
521void __xfrm_state_destroy(struct xfrm_state *x)
522{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800523 struct net *net = xs_net(x);
524
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700525 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 spin_lock_bh(&xfrm_state_gc_lock);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800528 hlist_add_head(&x->gclist, &net->xfrm.state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 spin_unlock_bh(&xfrm_state_gc_lock);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800530 schedule_work(&net->xfrm.state_gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531}
532EXPORT_SYMBOL(__xfrm_state_destroy);
533
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800534int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800536 struct net *net = xs_net(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700537 int err = -ESRCH;
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 if (x->km.state != XFRM_STATE_DEAD) {
540 x->km.state = XFRM_STATE_DEAD;
541 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700542 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700543 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700544 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700545 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700546 hlist_del(&x->byspi);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800547 net->xfrm.state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 /* All xfrm_state objects are created by xfrm_state_alloc.
551 * The xfrm_state_alloc call gives a reference, and that
552 * is what we are dropping here.
553 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800554 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700555 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700557
558 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800560EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700562int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700564 int err;
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700569
570 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571}
572EXPORT_SYMBOL(xfrm_state_delete);
573
Joy Latten4aa2e622007-06-04 19:05:57 -0400574#ifdef CONFIG_SECURITY_NETWORK_XFRM
575static inline int
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800576xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
Joy Latten4aa2e622007-06-04 19:05:57 -0400578 int i, err = 0;
579
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800580 for (i = 0; i <= net->xfrm.state_hmask; i++) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400581 struct hlist_node *entry;
582 struct xfrm_state *x;
583
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800584 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400585 if (xfrm_id_proto_match(x->id.proto, proto) &&
586 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700587 xfrm_audit_state_delete(x, 0,
588 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400589 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700590 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400591 return err;
592 }
593 }
594 }
595
596 return err;
597}
598#else
599static inline int
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800600xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
Joy Latten4aa2e622007-06-04 19:05:57 -0400601{
602 return 0;
603}
604#endif
605
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800606int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
Joy Latten4aa2e622007-06-04 19:05:57 -0400607{
608 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800611 err = xfrm_state_flush_secctx_check(net, proto, audit_info);
Joy Latten4aa2e622007-06-04 19:05:57 -0400612 if (err)
613 goto out;
614
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800615 for (i = 0; i <= net->xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700616 struct hlist_node *entry;
617 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618restart:
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800619 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700621 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 xfrm_state_hold(x);
623 spin_unlock_bh(&xfrm_state_lock);
624
Joy Latten161a09e2006-11-27 13:11:54 -0600625 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700626 xfrm_audit_state_delete(x, err ? 0 : 1,
627 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400628 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700629 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 xfrm_state_put(x);
631
632 spin_lock_bh(&xfrm_state_lock);
633 goto restart;
634 }
635 }
636 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400637 err = 0;
638
639out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 spin_unlock_bh(&xfrm_state_lock);
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800641 wake_up(&net->xfrm.km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400642 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644EXPORT_SYMBOL(xfrm_state_flush);
645
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700646void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700647{
648 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800649 si->sadcnt = init_net.xfrm.state_num;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800650 si->sadhcnt = init_net.xfrm.state_hmask;
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700651 si->sadhmcnt = xfrm_state_hashmax;
652 spin_unlock_bh(&xfrm_state_lock);
653}
654EXPORT_SYMBOL(xfrm_sad_getinfo);
655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656static int
657xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
658 struct xfrm_tmpl *tmpl,
659 xfrm_address_t *daddr, xfrm_address_t *saddr,
660 unsigned short family)
661{
662 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
663 if (!afinfo)
664 return -1;
665 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
666 xfrm_state_put_afinfo(afinfo);
667 return 0;
668}
669
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800670static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Milleredcd5822006-08-24 00:42:45 -0700671{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800672 unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700673 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700674 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700675
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800676 hlist_for_each_entry(x, entry, net->xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700677 if (x->props.family != family ||
678 x->id.spi != spi ||
679 x->id.proto != proto)
680 continue;
681
682 switch (family) {
683 case AF_INET:
684 if (x->id.daddr.a4 != daddr->a4)
685 continue;
686 break;
687 case AF_INET6:
688 if (!ipv6_addr_equal((struct in6_addr *)daddr,
689 (struct in6_addr *)
690 x->id.daddr.a6))
691 continue;
692 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700693 }
David S. Milleredcd5822006-08-24 00:42:45 -0700694
695 xfrm_state_hold(x);
696 return x;
697 }
698
699 return NULL;
700}
701
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800702static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
David S. Milleredcd5822006-08-24 00:42:45 -0700703{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800704 unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700705 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700706 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700707
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800708 hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700709 if (x->props.family != family ||
710 x->id.proto != proto)
711 continue;
712
713 switch (family) {
714 case AF_INET:
715 if (x->id.daddr.a4 != daddr->a4 ||
716 x->props.saddr.a4 != saddr->a4)
717 continue;
718 break;
719 case AF_INET6:
720 if (!ipv6_addr_equal((struct in6_addr *)daddr,
721 (struct in6_addr *)
722 x->id.daddr.a6) ||
723 !ipv6_addr_equal((struct in6_addr *)saddr,
724 (struct in6_addr *)
725 x->props.saddr.a6))
726 continue;
727 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700728 }
David S. Milleredcd5822006-08-24 00:42:45 -0700729
730 xfrm_state_hold(x);
731 return x;
732 }
733
734 return NULL;
735}
736
737static inline struct xfrm_state *
738__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
739{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800740 struct net *net = xs_net(x);
741
David S. Milleredcd5822006-08-24 00:42:45 -0700742 if (use_spi)
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800743 return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi,
David S. Milleredcd5822006-08-24 00:42:45 -0700744 x->id.proto, family);
745 else
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800746 return __xfrm_state_lookup_byaddr(net, &x->id.daddr,
David S. Milleredcd5822006-08-24 00:42:45 -0700747 &x->props.saddr,
748 x->id.proto, family);
749}
750
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800751static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700752{
753 if (have_hash_collision &&
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800754 (net->xfrm.state_hmask + 1) < xfrm_state_hashmax &&
755 net->xfrm.state_num > net->xfrm.state_hmask)
756 schedule_work(&net->xfrm.state_hash_work);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700757}
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900760xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 struct flowi *fl, struct xfrm_tmpl *tmpl,
762 struct xfrm_policy *pol, int *err,
763 unsigned short family)
764{
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800765 struct net *net = xp_net(pol);
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);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800776 h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family);
777 hlist_for_each_entry(x, entry, 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 &&
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800821 (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi,
David S. Milleredcd5822006-08-24 00:42:45 -0700822 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 Dobriyan5447c5e2008-11-25 17:31:51 -0800827 x = xfrm_state_alloc(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 Dobriyan5447c5e2008-11-25 17:31:51 -0800846 list_add(&x->km.all, &net->xfrm.state_all);
847 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
848 h = xfrm_src_hash(net, daddr, saddr, family);
849 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (x->id.spi) {
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800851 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family);
852 hlist_add_head(&x->byspi, 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 Dobriyan5447c5e2008-11-25 17:31:51 -0800857 net->xfrm.state_num++;
858 xfrm_hash_grow_check(net, 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 *
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800878xfrm_stateonly_find(struct net *net,
879 xfrm_address_t *daddr, xfrm_address_t *saddr,
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700880 unsigned short family, u8 mode, u8 proto, u32 reqid)
881{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800882 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700883 struct xfrm_state *rx = NULL, *x = NULL;
884 struct hlist_node *entry;
885
886 spin_lock(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800887 h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
888 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700889 if (x->props.family == family &&
890 x->props.reqid == reqid &&
891 !(x->props.flags & XFRM_STATE_WILDRECV) &&
892 xfrm_state_addr_check(x, daddr, saddr, family) &&
893 mode == x->props.mode &&
894 proto == x->id.proto &&
895 x->km.state == XFRM_STATE_VALID) {
896 rx = x;
897 break;
898 }
899 }
900
901 if (rx)
902 xfrm_state_hold(rx);
903 spin_unlock(&xfrm_state_lock);
904
905
906 return rx;
907}
908EXPORT_SYMBOL(xfrm_stateonly_find);
909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910static void __xfrm_state_insert(struct xfrm_state *x)
911{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800912 struct net *net = xs_net(x);
David S. Millera624c102006-08-24 03:24:33 -0700913 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
David S. Miller9d4a7062006-08-24 03:18:09 -0700915 x->genid = ++xfrm_state_genid;
916
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800917 list_add(&x->km.all, &net->xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800918
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800919 h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
David S. Millerc1969f22006-08-24 04:00:03 -0700920 x->props.reqid, x->props.family);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800921 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800923 h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
924 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700926 if (x->id.spi) {
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800927 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700928 x->props.family);
929
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800930 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700931 }
932
David S. Millera47f0ce2006-08-24 03:54:22 -0700933 mod_timer(&x->timer, jiffies + HZ);
934 if (x->replay_maxage)
935 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800936
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800937 wake_up(&net->xfrm.km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700938
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800939 net->xfrm.state_num++;
David S. Millerf034b5d2006-08-24 03:08:07 -0700940
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800941 xfrm_hash_grow_check(net, x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
David S. Millerc7f5ea32006-08-24 03:29:04 -0700944/* xfrm_state_lock is held */
945static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
946{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800947 struct net *net = xs_net(xnew);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700948 unsigned short family = xnew->props.family;
949 u32 reqid = xnew->props.reqid;
950 struct xfrm_state *x;
951 struct hlist_node *entry;
952 unsigned int h;
953
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800954 h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
955 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700956 if (x->props.family == family &&
957 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700958 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
959 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700960 x->genid = xfrm_state_genid;
961 }
962}
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964void xfrm_state_insert(struct xfrm_state *x)
965{
966 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700967 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 __xfrm_state_insert(x);
969 spin_unlock_bh(&xfrm_state_lock);
970}
971EXPORT_SYMBOL(xfrm_state_insert);
972
David S. Miller27708342006-08-24 00:13:10 -0700973/* xfrm_state_lock is held */
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800974static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
David S. Miller27708342006-08-24 00:13:10 -0700975{
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800976 unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700977 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700978 struct xfrm_state *x;
979
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800980 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700981 if (x->props.reqid != reqid ||
982 x->props.mode != mode ||
983 x->props.family != family ||
984 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700985 x->id.spi != 0 ||
986 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700987 continue;
988
989 switch (family) {
990 case AF_INET:
991 if (x->id.daddr.a4 != daddr->a4 ||
992 x->props.saddr.a4 != saddr->a4)
993 continue;
994 break;
995 case AF_INET6:
996 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
997 (struct in6_addr *)daddr) ||
998 !ipv6_addr_equal((struct in6_addr *)
999 x->props.saddr.a6,
1000 (struct in6_addr *)saddr))
1001 continue;
1002 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001003 }
David S. Miller27708342006-08-24 00:13:10 -07001004
1005 xfrm_state_hold(x);
1006 return x;
1007 }
1008
1009 if (!create)
1010 return NULL;
1011
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001012 x = xfrm_state_alloc(net);
David S. Miller27708342006-08-24 00:13:10 -07001013 if (likely(x)) {
1014 switch (family) {
1015 case AF_INET:
1016 x->sel.daddr.a4 = daddr->a4;
1017 x->sel.saddr.a4 = saddr->a4;
1018 x->sel.prefixlen_d = 32;
1019 x->sel.prefixlen_s = 32;
1020 x->props.saddr.a4 = saddr->a4;
1021 x->id.daddr.a4 = daddr->a4;
1022 break;
1023
1024 case AF_INET6:
1025 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1026 (struct in6_addr *)daddr);
1027 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1028 (struct in6_addr *)saddr);
1029 x->sel.prefixlen_d = 128;
1030 x->sel.prefixlen_s = 128;
1031 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1032 (struct in6_addr *)saddr);
1033 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1034 (struct in6_addr *)daddr);
1035 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001036 }
David S. Miller27708342006-08-24 00:13:10 -07001037
1038 x->km.state = XFRM_STATE_ACQ;
1039 x->id.proto = proto;
1040 x->props.family = family;
1041 x->props.mode = mode;
1042 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001043 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001044 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001045 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001046 add_timer(&x->timer);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001047 list_add(&x->km.all, &net->xfrm.state_all);
1048 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
1049 h = xfrm_src_hash(net, daddr, saddr, family);
1050 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001051
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001052 net->xfrm.state_num++;
David S. Miller918049f2006-10-12 22:03:24 -07001053
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001054 xfrm_hash_grow_check(net, x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001055 }
1056
1057 return x;
1058}
1059
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001060static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062int xfrm_state_add(struct xfrm_state *x)
1063{
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001064 struct net *net = xs_net(x);
David S. Miller37b08e32008-09-02 20:14:15 -07001065 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 int family;
1067 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001068 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
David S. Miller37b08e32008-09-02 20:14:15 -07001072 to_put = NULL;
1073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 spin_lock_bh(&xfrm_state_lock);
1075
David S. Milleredcd5822006-08-24 00:42:45 -07001076 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001078 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 x1 = NULL;
1080 err = -EEXIST;
1081 goto out;
1082 }
1083
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001084 if (use_spi && x->km.seq) {
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001085 x1 = __xfrm_find_acq_byseq(net, x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001086 if (x1 && ((x1->id.proto != x->id.proto) ||
1087 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001088 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 x1 = NULL;
1090 }
1091 }
1092
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001093 if (use_spi && !x1)
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001094 x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid,
David S. Miller27708342006-08-24 00:13:10 -07001095 x->id.proto,
1096 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
David S. Millerc7f5ea32006-08-24 03:29:04 -07001098 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 __xfrm_state_insert(x);
1100 err = 0;
1101
1102out:
1103 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 if (x1) {
1106 xfrm_state_delete(x1);
1107 xfrm_state_put(x1);
1108 }
1109
David S. Miller37b08e32008-09-02 20:14:15 -07001110 if (to_put)
1111 xfrm_state_put(to_put);
1112
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return err;
1114}
1115EXPORT_SYMBOL(xfrm_state_add);
1116
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001117#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001118static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001119{
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001120 struct net *net = xs_net(orig);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001121 int err = -ENOMEM;
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001122 struct xfrm_state *x = xfrm_state_alloc(net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001123 if (!x)
1124 goto error;
1125
1126 memcpy(&x->id, &orig->id, sizeof(x->id));
1127 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1128 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1129 x->props.mode = orig->props.mode;
1130 x->props.replay_window = orig->props.replay_window;
1131 x->props.reqid = orig->props.reqid;
1132 x->props.family = orig->props.family;
1133 x->props.saddr = orig->props.saddr;
1134
1135 if (orig->aalg) {
1136 x->aalg = xfrm_algo_clone(orig->aalg);
1137 if (!x->aalg)
1138 goto error;
1139 }
1140 x->props.aalgo = orig->props.aalgo;
1141
1142 if (orig->ealg) {
1143 x->ealg = xfrm_algo_clone(orig->ealg);
1144 if (!x->ealg)
1145 goto error;
1146 }
1147 x->props.ealgo = orig->props.ealgo;
1148
1149 if (orig->calg) {
1150 x->calg = xfrm_algo_clone(orig->calg);
1151 if (!x->calg)
1152 goto error;
1153 }
1154 x->props.calgo = orig->props.calgo;
1155
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001156 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001157 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1158 if (!x->encap)
1159 goto error;
1160 }
1161
1162 if (orig->coaddr) {
1163 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1164 GFP_KERNEL);
1165 if (!x->coaddr)
1166 goto error;
1167 }
1168
1169 err = xfrm_init_state(x);
1170 if (err)
1171 goto error;
1172
1173 x->props.flags = orig->props.flags;
1174
1175 x->curlft.add_time = orig->curlft.add_time;
1176 x->km.state = orig->km.state;
1177 x->km.seq = orig->km.seq;
1178
1179 return x;
1180
1181 error:
1182 if (errp)
1183 *errp = err;
1184 if (x) {
1185 kfree(x->aalg);
1186 kfree(x->ealg);
1187 kfree(x->calg);
1188 kfree(x->encap);
1189 kfree(x->coaddr);
1190 }
1191 kfree(x);
1192 return NULL;
1193}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001194
1195/* xfrm_state_lock is held */
1196struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1197{
1198 unsigned int h;
1199 struct xfrm_state *x;
1200 struct hlist_node *entry;
1201
1202 if (m->reqid) {
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -08001203 h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr,
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001204 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001205 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001206 if (x->props.mode != m->mode ||
1207 x->id.proto != m->proto)
1208 continue;
1209 if (m->reqid && x->props.reqid != m->reqid)
1210 continue;
1211 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1212 m->old_family) ||
1213 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1214 m->old_family))
1215 continue;
1216 xfrm_state_hold(x);
1217 return x;
1218 }
1219 } else {
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -08001220 h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr,
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001221 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001222 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001223 if (x->props.mode != m->mode ||
1224 x->id.proto != m->proto)
1225 continue;
1226 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1227 m->old_family) ||
1228 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1229 m->old_family))
1230 continue;
1231 xfrm_state_hold(x);
1232 return x;
1233 }
1234 }
1235
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001236 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001237}
1238EXPORT_SYMBOL(xfrm_migrate_state_find);
1239
1240struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1241 struct xfrm_migrate *m)
1242{
1243 struct xfrm_state *xc;
1244 int err;
1245
1246 xc = xfrm_state_clone(x, &err);
1247 if (!xc)
1248 return NULL;
1249
1250 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1251 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1252
1253 /* add state */
1254 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1255 /* a care is needed when the destination address of the
1256 state is to be updated as it is a part of triplet */
1257 xfrm_state_insert(xc);
1258 } else {
1259 if ((err = xfrm_state_add(xc)) < 0)
1260 goto error;
1261 }
1262
1263 return xc;
1264error:
1265 kfree(xc);
1266 return NULL;
1267}
1268EXPORT_SYMBOL(xfrm_state_migrate);
1269#endif
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271int xfrm_state_update(struct xfrm_state *x)
1272{
David S. Miller37b08e32008-09-02 20:14:15 -07001273 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001275 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
David S. Miller37b08e32008-09-02 20:14:15 -07001277 to_put = NULL;
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001280 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
1282 err = -ESRCH;
1283 if (!x1)
1284 goto out;
1285
1286 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001287 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 err = -EEXIST;
1289 goto out;
1290 }
1291
1292 if (x1->km.state == XFRM_STATE_ACQ) {
1293 __xfrm_state_insert(x);
1294 x = NULL;
1295 }
1296 err = 0;
1297
1298out:
1299 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
David S. Miller37b08e32008-09-02 20:14:15 -07001301 if (to_put)
1302 xfrm_state_put(to_put);
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (err)
1305 return err;
1306
1307 if (!x) {
1308 xfrm_state_delete(x1);
1309 xfrm_state_put(x1);
1310 return 0;
1311 }
1312
1313 err = -EINVAL;
1314 spin_lock_bh(&x1->lock);
1315 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1316 if (x->encap && x1->encap)
1317 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001318 if (x->coaddr && x1->coaddr) {
1319 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1320 }
1321 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1322 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1324 x1->km.dying = 0;
1325
David S. Millera47f0ce2006-08-24 03:54:22 -07001326 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (x1->curlft.use_time)
1328 xfrm_state_check_expire(x1);
1329
1330 err = 0;
1331 }
1332 spin_unlock_bh(&x1->lock);
1333
1334 xfrm_state_put(x1);
1335
1336 return err;
1337}
1338EXPORT_SYMBOL(xfrm_state_update);
1339
1340int xfrm_state_check_expire(struct xfrm_state *x)
1341{
1342 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001343 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 if (x->km.state != XFRM_STATE_VALID)
1346 return -EINVAL;
1347
1348 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1349 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001350 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001351 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 return -EINVAL;
1353 }
1354
1355 if (!x->km.dying &&
1356 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001357 x->curlft.packets >= x->lft.soft_packet_limit)) {
1358 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001359 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 return 0;
1362}
1363EXPORT_SYMBOL(xfrm_state_check_expire);
1364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365struct xfrm_state *
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001366xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 unsigned short family)
1368{
1369 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001372 x = __xfrm_state_lookup(net, daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 return x;
1375}
1376EXPORT_SYMBOL(xfrm_state_lookup);
1377
1378struct xfrm_state *
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001379xfrm_state_lookup_byaddr(struct net *net,
1380 xfrm_address_t *daddr, xfrm_address_t *saddr,
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001381 u8 proto, unsigned short family)
1382{
1383 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001384
1385 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001386 x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001387 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001388 return x;
1389}
1390EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1391
1392struct xfrm_state *
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001393xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto,
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001394 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 int create, unsigned short family)
1396{
1397 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001400 x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001402
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 return x;
1404}
1405EXPORT_SYMBOL(xfrm_find_acq);
1406
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001407#ifdef CONFIG_XFRM_SUB_POLICY
1408int
1409xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1410 unsigned short family)
1411{
1412 int err = 0;
1413 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1414 if (!afinfo)
1415 return -EAFNOSUPPORT;
1416
1417 spin_lock_bh(&xfrm_state_lock);
1418 if (afinfo->tmpl_sort)
1419 err = afinfo->tmpl_sort(dst, src, n);
1420 spin_unlock_bh(&xfrm_state_lock);
1421 xfrm_state_put_afinfo(afinfo);
1422 return err;
1423}
1424EXPORT_SYMBOL(xfrm_tmpl_sort);
1425
1426int
1427xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1428 unsigned short family)
1429{
1430 int err = 0;
1431 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1432 if (!afinfo)
1433 return -EAFNOSUPPORT;
1434
1435 spin_lock_bh(&xfrm_state_lock);
1436 if (afinfo->state_sort)
1437 err = afinfo->state_sort(dst, src, n);
1438 spin_unlock_bh(&xfrm_state_lock);
1439 xfrm_state_put_afinfo(afinfo);
1440 return err;
1441}
1442EXPORT_SYMBOL(xfrm_state_sort);
1443#endif
1444
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445/* Silly enough, but I'm lazy to build resolution list */
1446
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001447static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448{
1449 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001451 for (i = 0; i <= net->xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001452 struct hlist_node *entry;
1453 struct xfrm_state *x;
1454
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001455 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001456 if (x->km.seq == seq &&
1457 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 xfrm_state_hold(x);
1459 return x;
1460 }
1461 }
1462 }
1463 return NULL;
1464}
1465
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001466struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467{
1468 struct xfrm_state *x;
1469
1470 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001471 x = __xfrm_find_acq_byseq(net, seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 spin_unlock_bh(&xfrm_state_lock);
1473 return x;
1474}
1475EXPORT_SYMBOL(xfrm_find_acq_byseq);
1476
1477u32 xfrm_get_acqseq(void)
1478{
1479 u32 res;
1480 static u32 acqseq;
1481 static DEFINE_SPINLOCK(acqseq_lock);
1482
1483 spin_lock_bh(&acqseq_lock);
1484 res = (++acqseq ? : ++acqseq);
1485 spin_unlock_bh(&acqseq_lock);
1486 return res;
1487}
1488EXPORT_SYMBOL(xfrm_get_acqseq);
1489
Herbert Xu658b2192007-10-09 13:29:52 -07001490int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001492 struct net *net = xs_net(x);
David S. Millerf034b5d2006-08-24 03:08:07 -07001493 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001495 int err = -ENOENT;
1496 __be32 minspi = htonl(low);
1497 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Herbert Xu658b2192007-10-09 13:29:52 -07001499 spin_lock_bh(&x->lock);
1500 if (x->km.state == XFRM_STATE_DEAD)
1501 goto unlock;
1502
1503 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001505 goto unlock;
1506
1507 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
1509 if (minspi == maxspi) {
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001510 x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 if (x0) {
1512 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001513 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 }
1515 x->id.spi = minspi;
1516 } else {
1517 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001518 for (h=0; h<high-low+1; h++) {
1519 spi = low + net_random()%(high-low+1);
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001520 x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 if (x0 == NULL) {
1522 x->id.spi = htonl(spi);
1523 break;
1524 }
1525 xfrm_state_put(x0);
1526 }
1527 }
1528 if (x->id.spi) {
1529 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan12604d82008-11-25 17:31:18 -08001530 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
1531 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001533
1534 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 }
Herbert Xu658b2192007-10-09 13:29:52 -07001536
1537unlock:
1538 spin_unlock_bh(&x->lock);
1539
1540 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541}
1542EXPORT_SYMBOL(xfrm_alloc_spi);
1543
Alexey Dobriyan284fa7d2008-11-25 17:32:14 -08001544int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
Timo Teras4c563f72008-02-28 21:31:08 -08001545 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 void *data)
1547{
Herbert Xu12a169e2008-10-01 07:03:24 -07001548 struct xfrm_state *state;
1549 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 int err = 0;
1551
Herbert Xu12a169e2008-10-01 07:03:24 -07001552 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001553 return 0;
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001556 if (list_empty(&walk->all))
Alexey Dobriyan284fa7d2008-11-25 17:32:14 -08001557 x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001558 else
1559 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan284fa7d2008-11-25 17:32:14 -08001560 list_for_each_entry_from(x, &net->xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001561 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001562 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001563 state = container_of(x, struct xfrm_state, km);
1564 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001565 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001566 err = func(state, walk->seq, data);
1567 if (err) {
1568 list_move_tail(&walk->all, &x->all);
1569 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001571 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001573 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 err = -ENOENT;
1575 goto out;
1576 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001577 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578out:
1579 spin_unlock_bh(&xfrm_state_lock);
1580 return err;
1581}
1582EXPORT_SYMBOL(xfrm_state_walk);
1583
Herbert Xu5c182452008-09-22 19:48:19 -07001584void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1585{
Herbert Xu12a169e2008-10-01 07:03:24 -07001586 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001587 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001588 walk->state = XFRM_STATE_DEAD;
1589 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001590}
1591EXPORT_SYMBOL(xfrm_state_walk_init);
1592
Herbert Xuabb81c42008-09-09 19:58:29 -07001593void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1594{
Herbert Xu12a169e2008-10-01 07:03:24 -07001595 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001596 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001597
Herbert Xu12a169e2008-10-01 07:03:24 -07001598 spin_lock_bh(&xfrm_state_lock);
1599 list_del(&walk->all);
1600 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001601}
1602EXPORT_SYMBOL(xfrm_state_walk_done);
1603
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001604
1605void xfrm_replay_notify(struct xfrm_state *x, int event)
1606{
1607 struct km_event c;
1608 /* we send notify messages in case
1609 * 1. we updated on of the sequence numbers, and the seqno difference
1610 * is at least x->replay_maxdiff, in this case we also update the
1611 * timeout of our timer function
1612 * 2. if x->replay_maxage has elapsed since last update,
1613 * and there were changes
1614 *
1615 * The state structure must be locked!
1616 */
1617
1618 switch (event) {
1619 case XFRM_REPLAY_UPDATE:
1620 if (x->replay_maxdiff &&
1621 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001622 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1623 if (x->xflags & XFRM_TIME_DEFER)
1624 event = XFRM_REPLAY_TIMEOUT;
1625 else
1626 return;
1627 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001628
1629 break;
1630
1631 case XFRM_REPLAY_TIMEOUT:
1632 if ((x->replay.seq == x->preplay.seq) &&
1633 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001634 (x->replay.oseq == x->preplay.oseq)) {
1635 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001636 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001637 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001638
1639 break;
1640 }
1641
1642 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1643 c.event = XFRM_MSG_NEWAE;
1644 c.data.aevent = event;
1645 km_state_notify(x, &c);
1646
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001647 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001648 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001649 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001650}
1651
1652static void xfrm_replay_timer_handler(unsigned long data)
1653{
1654 struct xfrm_state *x = (struct xfrm_state*)data;
1655
1656 spin_lock(&x->lock);
1657
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001658 if (x->km.state == XFRM_STATE_VALID) {
Alexey Dobriyana6483b72008-11-25 17:38:20 -08001659 if (xfrm_aevent_is_on(xs_net(x)))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001660 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1661 else
1662 x->xflags |= XFRM_TIME_DEFER;
1663 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001664
1665 spin_unlock(&x->lock);
1666}
1667
Paul Mooreafeb14b2007-12-21 14:58:11 -08001668int xfrm_replay_check(struct xfrm_state *x,
1669 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670{
1671 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001672 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001675 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
1677 if (likely(seq > x->replay.seq))
1678 return 0;
1679
1680 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001681 if (diff >= min_t(unsigned int, x->props.replay_window,
1682 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001684 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
1686
1687 if (x->replay.bitmap & (1U << diff)) {
1688 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001689 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001692
1693err:
1694 xfrm_audit_state_replay(x, skb, net_seq);
1695 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
Al Viro61f46272006-09-27 18:48:33 -07001698void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699{
1700 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001701 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 if (seq > x->replay.seq) {
1704 diff = seq - x->replay.seq;
1705 if (diff < x->props.replay_window)
1706 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1707 else
1708 x->replay.bitmap = 1;
1709 x->replay.seq = seq;
1710 } else {
1711 diff = x->replay.seq - seq;
1712 x->replay.bitmap |= (1U << diff);
1713 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001714
Alexey Dobriyana6483b72008-11-25 17:38:20 -08001715 if (xfrm_aevent_is_on(xs_net(x)))
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001716 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
Denis Chengdf018122007-12-07 00:51:11 -08001719static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720static DEFINE_RWLOCK(xfrm_km_lock);
1721
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001722void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723{
1724 struct xfrm_mgr *km;
1725
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001726 read_lock(&xfrm_km_lock);
1727 list_for_each_entry(km, &xfrm_km_list, list)
1728 if (km->notify_policy)
1729 km->notify_policy(xp, dir, c);
1730 read_unlock(&xfrm_km_lock);
1731}
1732
1733void km_state_notify(struct xfrm_state *x, struct km_event *c)
1734{
1735 struct xfrm_mgr *km;
1736 read_lock(&xfrm_km_lock);
1737 list_for_each_entry(km, &xfrm_km_list, list)
1738 if (km->notify)
1739 km->notify(x, c);
1740 read_unlock(&xfrm_km_lock);
1741}
1742
1743EXPORT_SYMBOL(km_policy_notify);
1744EXPORT_SYMBOL(km_state_notify);
1745
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001746void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001747{
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001748 struct net *net = xs_net(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001749 struct km_event c;
1750
Herbert Xubf088672005-06-18 22:44:00 -07001751 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001752 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001753 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001754 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 if (hard)
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001757 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758}
1759
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001760EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001761/*
1762 * We send to all registered managers regardless of failure
1763 * We are happy with one success
1764*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001765int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001767 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 struct xfrm_mgr *km;
1769
1770 read_lock(&xfrm_km_lock);
1771 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001772 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1773 if (!acqret)
1774 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 }
1776 read_unlock(&xfrm_km_lock);
1777 return err;
1778}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001779EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Al Viro5d36b182006-11-08 00:24:06 -08001781int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782{
1783 int err = -EINVAL;
1784 struct xfrm_mgr *km;
1785
1786 read_lock(&xfrm_km_lock);
1787 list_for_each_entry(km, &xfrm_km_list, list) {
1788 if (km->new_mapping)
1789 err = km->new_mapping(x, ipaddr, sport);
1790 if (!err)
1791 break;
1792 }
1793 read_unlock(&xfrm_km_lock);
1794 return err;
1795}
1796EXPORT_SYMBOL(km_new_mapping);
1797
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001798void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799{
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001800 struct net *net = xp_net(pol);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001801 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Herbert Xubf088672005-06-18 22:44:00 -07001803 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001804 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001805 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001806 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
1808 if (hard)
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001809 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810}
David S. Millera70fcb02006-03-20 19:18:52 -08001811EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001813#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001814int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001815 struct xfrm_migrate *m, int num_migrate,
1816 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001817{
1818 int err = -EINVAL;
1819 int ret;
1820 struct xfrm_mgr *km;
1821
1822 read_lock(&xfrm_km_lock);
1823 list_for_each_entry(km, &xfrm_km_list, list) {
1824 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001825 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001826 if (!ret)
1827 err = ret;
1828 }
1829 }
1830 read_unlock(&xfrm_km_lock);
1831 return err;
1832}
1833EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001834#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001835
Alexey Dobriyandb983c12008-11-25 17:51:01 -08001836int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001837{
1838 int err = -EINVAL;
1839 int ret;
1840 struct xfrm_mgr *km;
1841
1842 read_lock(&xfrm_km_lock);
1843 list_for_each_entry(km, &xfrm_km_list, list) {
1844 if (km->report) {
Alexey Dobriyandb983c12008-11-25 17:51:01 -08001845 ret = km->report(net, proto, sel, addr);
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001846 if (!ret)
1847 err = ret;
1848 }
1849 }
1850 read_unlock(&xfrm_km_lock);
1851 return err;
1852}
1853EXPORT_SYMBOL(km_report);
1854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1856{
1857 int err;
1858 u8 *data;
1859 struct xfrm_mgr *km;
1860 struct xfrm_policy *pol = NULL;
1861
1862 if (optlen <= 0 || optlen > PAGE_SIZE)
1863 return -EMSGSIZE;
1864
1865 data = kmalloc(optlen, GFP_KERNEL);
1866 if (!data)
1867 return -ENOMEM;
1868
1869 err = -EFAULT;
1870 if (copy_from_user(data, optval, optlen))
1871 goto out;
1872
1873 err = -EINVAL;
1874 read_lock(&xfrm_km_lock);
1875 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001876 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 optlen, &err);
1878 if (err >= 0)
1879 break;
1880 }
1881 read_unlock(&xfrm_km_lock);
1882
1883 if (err >= 0) {
1884 xfrm_sk_policy_insert(sk, err, pol);
1885 xfrm_pol_put(pol);
1886 err = 0;
1887 }
1888
1889out:
1890 kfree(data);
1891 return err;
1892}
1893EXPORT_SYMBOL(xfrm_user_policy);
1894
1895int xfrm_register_km(struct xfrm_mgr *km)
1896{
1897 write_lock_bh(&xfrm_km_lock);
1898 list_add_tail(&km->list, &xfrm_km_list);
1899 write_unlock_bh(&xfrm_km_lock);
1900 return 0;
1901}
1902EXPORT_SYMBOL(xfrm_register_km);
1903
1904int xfrm_unregister_km(struct xfrm_mgr *km)
1905{
1906 write_lock_bh(&xfrm_km_lock);
1907 list_del(&km->list);
1908 write_unlock_bh(&xfrm_km_lock);
1909 return 0;
1910}
1911EXPORT_SYMBOL(xfrm_unregister_km);
1912
1913int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1914{
1915 int err = 0;
1916 if (unlikely(afinfo == NULL))
1917 return -EINVAL;
1918 if (unlikely(afinfo->family >= NPROTO))
1919 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001920 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1922 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001923 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001925 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 return err;
1927}
1928EXPORT_SYMBOL(xfrm_state_register_afinfo);
1929
1930int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1931{
1932 int err = 0;
1933 if (unlikely(afinfo == NULL))
1934 return -EINVAL;
1935 if (unlikely(afinfo->family >= NPROTO))
1936 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001937 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1939 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1940 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001941 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001944 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 return err;
1946}
1947EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1948
Herbert Xu17c2a422007-10-17 21:33:12 -07001949static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950{
1951 struct xfrm_state_afinfo *afinfo;
1952 if (unlikely(family >= NPROTO))
1953 return NULL;
1954 read_lock(&xfrm_state_afinfo_lock);
1955 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001956 if (unlikely(!afinfo))
1957 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 return afinfo;
1959}
1960
Herbert Xu17c2a422007-10-17 21:33:12 -07001961static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001962 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{
Herbert Xu546be242006-05-27 23:03:58 -07001964 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965}
1966
1967/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1968void xfrm_state_delete_tunnel(struct xfrm_state *x)
1969{
1970 if (x->tunnel) {
1971 struct xfrm_state *t = x->tunnel;
1972
1973 if (atomic_read(&t->tunnel_users) == 2)
1974 xfrm_state_delete(t);
1975 atomic_dec(&t->tunnel_users);
1976 xfrm_state_put(t);
1977 x->tunnel = NULL;
1978 }
1979}
1980EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1981
1982int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1983{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001984 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
Patrick McHardyc5c25232007-04-09 11:47:18 -07001986 spin_lock_bh(&x->lock);
1987 if (x->km.state == XFRM_STATE_VALID &&
1988 x->type && x->type->get_mtu)
1989 res = x->type->get_mtu(x, mtu);
1990 else
Patrick McHardy28121612007-06-18 22:30:15 -07001991 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001992 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 return res;
1994}
1995
Herbert Xu72cb6962005-06-20 13:18:08 -07001996int xfrm_init_state(struct xfrm_state *x)
1997{
Herbert Xud094cd82005-06-20 13:19:41 -07001998 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07001999 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07002000 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07002001 int err;
2002
Herbert Xud094cd82005-06-20 13:19:41 -07002003 err = -EAFNOSUPPORT;
2004 afinfo = xfrm_state_get_afinfo(family);
2005 if (!afinfo)
2006 goto error;
2007
2008 err = 0;
2009 if (afinfo->init_flags)
2010 err = afinfo->init_flags(x);
2011
2012 xfrm_state_put_afinfo(afinfo);
2013
2014 if (err)
2015 goto error;
2016
2017 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002018
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002019 if (x->sel.family != AF_UNSPEC) {
2020 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2021 if (inner_mode == NULL)
2022 goto error;
2023
2024 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2025 family != x->sel.family) {
2026 xfrm_put_mode(inner_mode);
2027 goto error;
2028 }
2029
2030 x->inner_mode = inner_mode;
2031 } else {
2032 struct xfrm_mode *inner_mode_iaf;
2033
2034 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2035 if (inner_mode == NULL)
2036 goto error;
2037
2038 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2039 xfrm_put_mode(inner_mode);
2040 goto error;
2041 }
2042
2043 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2044 if (inner_mode_iaf == NULL)
2045 goto error;
2046
2047 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2048 xfrm_put_mode(inner_mode_iaf);
2049 goto error;
2050 }
2051
2052 if (x->props.family == AF_INET) {
2053 x->inner_mode = inner_mode;
2054 x->inner_mode_iaf = inner_mode_iaf;
2055 } else {
2056 x->inner_mode = inner_mode_iaf;
2057 x->inner_mode_iaf = inner_mode;
2058 }
2059 }
Herbert Xu13996372007-10-17 21:35:51 -07002060
Herbert Xud094cd82005-06-20 13:19:41 -07002061 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002062 if (x->type == NULL)
2063 goto error;
2064
2065 err = x->type->init_state(x);
2066 if (err)
2067 goto error;
2068
Herbert Xu13996372007-10-17 21:35:51 -07002069 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2070 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002071 goto error;
2072
Herbert Xu72cb6962005-06-20 13:18:08 -07002073 x->km.state = XFRM_STATE_VALID;
2074
2075error:
2076 return err;
2077}
2078
2079EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002080
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002081int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082{
David S. Millerf034b5d2006-08-24 03:08:07 -07002083 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002085 INIT_LIST_HEAD(&net->xfrm.state_all);
2086
David S. Millerf034b5d2006-08-24 03:08:07 -07002087 sz = sizeof(struct hlist_head) * 8;
2088
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002089 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2090 if (!net->xfrm.state_bydst)
2091 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002092 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2093 if (!net->xfrm.state_bysrc)
2094 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002095 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2096 if (!net->xfrm.state_byspi)
2097 goto out_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002098 net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
David S. Millerf034b5d2006-08-24 03:08:07 -07002099
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08002100 net->xfrm.state_num = 0;
Alexey Dobriyan63082732008-11-25 17:19:07 -08002101 INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
Alexey Dobriyanb8a0ae22008-11-25 17:20:11 -08002102 INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
Alexey Dobriyanc7837142008-11-25 17:20:36 -08002103 INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
Alexey Dobriyan50a30652008-11-25 17:21:01 -08002104 init_waitqueue_head(&net->xfrm.km_waitq);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002105 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002106
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002107out_byspi:
2108 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002109out_bysrc:
2110 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002111out_bydst:
2112 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002113}
2114
2115void xfrm_state_fini(struct net *net)
2116{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002117 unsigned int sz;
2118
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002119 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002120
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002121 sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002122 WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2123 xfrm_hash_free(net->xfrm.state_byspi, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002124 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2125 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002126 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2127 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128}
2129
Joy Lattenab5f5e82007-09-17 11:51:22 -07002130#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002131static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2132 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002133{
Paul Moore68277ac2007-12-20 20:49:33 -08002134 struct xfrm_sec_ctx *ctx = x->security;
2135 u32 spi = ntohl(x->id.spi);
2136
2137 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002138 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002139 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002140
2141 switch(x->props.family) {
2142 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002143 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2144 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002145 break;
2146 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002147 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002148 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002149 break;
2150 }
Paul Moore68277ac2007-12-20 20:49:33 -08002151
2152 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002153}
2154
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002155static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2156 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002157{
2158 struct iphdr *iph4;
2159 struct ipv6hdr *iph6;
2160
2161 switch (family) {
2162 case AF_INET:
2163 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002164 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2165 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002166 break;
2167 case AF_INET6:
2168 iph6 = ipv6_hdr(skb);
2169 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002170 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002171 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002172 iph6->flow_lbl[0] & 0x0f,
2173 iph6->flow_lbl[1],
2174 iph6->flow_lbl[2]);
2175 break;
2176 }
2177}
2178
Paul Moore68277ac2007-12-20 20:49:33 -08002179void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002180 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002181{
2182 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002183
Paul Mooreafeb14b2007-12-21 14:58:11 -08002184 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002185 if (audit_buf == NULL)
2186 return;
Eric Paris25323862008-04-18 10:09:25 -04002187 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002188 xfrm_audit_helper_sainfo(x, audit_buf);
2189 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002190 audit_log_end(audit_buf);
2191}
2192EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2193
Paul Moore68277ac2007-12-20 20:49:33 -08002194void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002195 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002196{
2197 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002198
Paul Mooreafeb14b2007-12-21 14:58:11 -08002199 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002200 if (audit_buf == NULL)
2201 return;
Eric Paris25323862008-04-18 10:09:25 -04002202 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002203 xfrm_audit_helper_sainfo(x, audit_buf);
2204 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002205 audit_log_end(audit_buf);
2206}
2207EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002208
2209void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2210 struct sk_buff *skb)
2211{
2212 struct audit_buffer *audit_buf;
2213 u32 spi;
2214
2215 audit_buf = xfrm_audit_start("SA-replay-overflow");
2216 if (audit_buf == NULL)
2217 return;
2218 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2219 /* don't record the sequence number because it's inherent in this kind
2220 * of audit message */
2221 spi = ntohl(x->id.spi);
2222 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2223 audit_log_end(audit_buf);
2224}
2225EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2226
2227static void xfrm_audit_state_replay(struct xfrm_state *x,
2228 struct sk_buff *skb, __be32 net_seq)
2229{
2230 struct audit_buffer *audit_buf;
2231 u32 spi;
2232
2233 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2234 if (audit_buf == NULL)
2235 return;
2236 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2237 spi = ntohl(x->id.spi);
2238 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2239 spi, spi, ntohl(net_seq));
2240 audit_log_end(audit_buf);
2241}
2242
2243void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2244{
2245 struct audit_buffer *audit_buf;
2246
2247 audit_buf = xfrm_audit_start("SA-notfound");
2248 if (audit_buf == NULL)
2249 return;
2250 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2251 audit_log_end(audit_buf);
2252}
2253EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2254
2255void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2256 __be32 net_spi, __be32 net_seq)
2257{
2258 struct audit_buffer *audit_buf;
2259 u32 spi;
2260
2261 audit_buf = xfrm_audit_start("SA-notfound");
2262 if (audit_buf == NULL)
2263 return;
2264 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2265 spi = ntohl(net_spi);
2266 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2267 spi, spi, ntohl(net_seq));
2268 audit_log_end(audit_buf);
2269}
2270EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2271
2272void xfrm_audit_state_icvfail(struct xfrm_state *x,
2273 struct sk_buff *skb, u8 proto)
2274{
2275 struct audit_buffer *audit_buf;
2276 __be32 net_spi;
2277 __be32 net_seq;
2278
2279 audit_buf = xfrm_audit_start("SA-icv-failure");
2280 if (audit_buf == NULL)
2281 return;
2282 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2283 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2284 u32 spi = ntohl(net_spi);
2285 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2286 spi, spi, ntohl(net_seq));
2287 }
2288 audit_log_end(audit_buf);
2289}
2290EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002291#endif /* CONFIG_AUDITSYSCALL */