blob: cd51e4e3d0238c6546a1e84a4baf9b7f28e7ddfa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * xfrm_state.c
3 *
4 * Changes:
5 * Mitsuru KANDA @USAGI
6 * Kazunori MIYAZAWA @USAGI
7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
8 * IPv6 support
9 * YOSHIFUJI Hideaki @USAGI
10 * Split up af-specific functions
11 * Derek Atkins <derek@ihtfp.com>
12 * Add UDP Encapsulation
Trent Jaegerdf718372005-12-13 23:12:27 -080013 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 */
15
16#include <linux/workqueue.h>
17#include <net/xfrm.h>
18#include <linux/pfkeyv2.h>
19#include <linux/ipsec.h>
20#include <linux/module.h>
David S. Millerf034b5d2006-08-24 03:08:07 -070021#include <linux/cache.h>
Paul Moore68277ac2007-12-20 20:49:33 -080022#include <linux/audit.h>
Jesper Juhlb5890d82007-08-10 15:20:21 -070023#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
David S. Miller44e36b42006-08-24 04:50:50 -070025#include "xfrm_hash.h"
26
David S. Milleree857a72006-03-20 19:18:37 -080027struct sock *xfrm_nl;
28EXPORT_SYMBOL(xfrm_nl);
29
David S. Miller01e67d02007-05-25 00:41:38 -070030u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME;
David S. Millera70fcb02006-03-20 19:18:52 -080031EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
32
David S. Miller01e67d02007-05-25 00:41:38 -070033u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE;
David S. Millera70fcb02006-03-20 19:18:52 -080034EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
35
David S. Miller01e67d02007-05-25 00:41:38 -070036u32 sysctl_xfrm_acq_expires __read_mostly = 30;
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/* Each xfrm_state may be linked to two tables:
39
40 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
David S. Millera624c102006-08-24 03:24:33 -070041 2. Hash table by (daddr,family,reqid) to find what SAs exist for given
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 destination/tunnel endpoint. (output)
43 */
44
45static DEFINE_SPINLOCK(xfrm_state_lock);
46
David S. Millerf034b5d2006-08-24 03:08:07 -070047static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
David S. Miller9d4a7062006-08-24 03:18:09 -070048static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Herbert Xu17c2a422007-10-17 21:33:12 -070050static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
51static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
52
Paul Mooreafeb14b2007-12-21 14:58:11 -080053#ifdef CONFIG_AUDITSYSCALL
54static void xfrm_audit_state_replay(struct xfrm_state *x,
55 struct sk_buff *skb, __be32 net_seq);
56#else
57#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
58#endif /* CONFIG_AUDITSYSCALL */
59
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080060static inline unsigned int xfrm_dst_hash(struct net *net,
61 xfrm_address_t *daddr,
David S. Millerc1969f22006-08-24 04:00:03 -070062 xfrm_address_t *saddr,
63 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070064 unsigned short family)
65{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080066 return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070067}
68
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080069static inline unsigned int xfrm_src_hash(struct net *net,
70 xfrm_address_t *daddr,
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070071 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070072 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070073{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080074 return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070075}
76
David S. Miller2575b652006-08-24 03:26:44 -070077static inline unsigned int
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080078xfrm_spi_hash(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070079{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -080080 return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070081}
82
David S. Millerf034b5d2006-08-24 03:08:07 -070083static void xfrm_hash_transfer(struct hlist_head *list,
84 struct hlist_head *ndsttable,
85 struct hlist_head *nsrctable,
86 struct hlist_head *nspitable,
87 unsigned int nhashmask)
88{
89 struct hlist_node *entry, *tmp;
90 struct xfrm_state *x;
91
92 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
93 unsigned int h;
94
David S. Millerc1969f22006-08-24 04:00:03 -070095 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
96 x->props.reqid, x->props.family,
97 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070098 hlist_add_head(&x->bydst, ndsttable+h);
99
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700100 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
101 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700102 nhashmask);
103 hlist_add_head(&x->bysrc, nsrctable+h);
104
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700105 if (x->id.spi) {
106 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
107 x->id.proto, x->props.family,
108 nhashmask);
109 hlist_add_head(&x->byspi, nspitable+h);
110 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700111 }
112}
113
Alexey Dobriyan63082732008-11-25 17:19:07 -0800114static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
David S. Millerf034b5d2006-08-24 03:08:07 -0700115{
Alexey Dobriyan63082732008-11-25 17:19:07 -0800116 return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
David S. Millerf034b5d2006-08-24 03:08:07 -0700117}
118
119static DEFINE_MUTEX(hash_resize_mutex);
120
Alexey Dobriyan63082732008-11-25 17:19:07 -0800121static void xfrm_hash_resize(struct work_struct *work)
David S. Millerf034b5d2006-08-24 03:08:07 -0700122{
Alexey Dobriyan63082732008-11-25 17:19:07 -0800123 struct net *net = container_of(work, struct net, xfrm.state_hash_work);
David S. Millerf034b5d2006-08-24 03:08:07 -0700124 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
125 unsigned long nsize, osize;
126 unsigned int nhashmask, ohashmask;
127 int i;
128
129 mutex_lock(&hash_resize_mutex);
130
Alexey Dobriyan63082732008-11-25 17:19:07 -0800131 nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
David S. Miller44e36b42006-08-24 04:50:50 -0700132 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700133 if (!ndst)
134 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700135 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700136 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700137 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700138 goto out_unlock;
139 }
David S. Miller44e36b42006-08-24 04:50:50 -0700140 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700141 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700142 xfrm_hash_free(ndst, nsize);
143 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700144 goto out_unlock;
145 }
146
147 spin_lock_bh(&xfrm_state_lock);
148
149 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
Alexey Dobriyan63082732008-11-25 17:19:07 -0800150 for (i = net->xfrm.state_hmask; i >= 0; i--)
151 xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
David S. Millerf034b5d2006-08-24 03:08:07 -0700152 nhashmask);
153
Alexey Dobriyan63082732008-11-25 17:19:07 -0800154 odst = net->xfrm.state_bydst;
155 osrc = net->xfrm.state_bysrc;
156 ospi = net->xfrm.state_byspi;
157 ohashmask = net->xfrm.state_hmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700158
Alexey Dobriyan63082732008-11-25 17:19:07 -0800159 net->xfrm.state_bydst = ndst;
160 net->xfrm.state_bysrc = nsrc;
161 net->xfrm.state_byspi = nspi;
162 net->xfrm.state_hmask = nhashmask;
David S. Millerf034b5d2006-08-24 03:08:07 -0700163
164 spin_unlock_bh(&xfrm_state_lock);
165
166 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700167 xfrm_hash_free(odst, osize);
168 xfrm_hash_free(osrc, osize);
169 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700170
171out_unlock:
172 mutex_unlock(&hash_resize_mutex);
173}
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
176static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static DEFINE_SPINLOCK(xfrm_state_gc_lock);
179
Jamal Hadi Salim53bc6b4d2006-03-20 19:17:03 -0800180int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800182int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b4d2006-03-20 19:17:03 -0800183void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700185static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
186{
187 struct xfrm_state_afinfo *afinfo;
188 if (unlikely(family >= NPROTO))
189 return NULL;
190 write_lock_bh(&xfrm_state_afinfo_lock);
191 afinfo = xfrm_state_afinfo[family];
192 if (unlikely(!afinfo))
193 write_unlock_bh(&xfrm_state_afinfo_lock);
194 return afinfo;
195}
196
197static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800198 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700199{
200 write_unlock_bh(&xfrm_state_afinfo_lock);
201}
202
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800203int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700204{
205 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800206 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700207 int err = 0;
208
209 if (unlikely(afinfo == NULL))
210 return -EAFNOSUPPORT;
211 typemap = afinfo->type_map;
212
213 if (likely(typemap[type->proto] == NULL))
214 typemap[type->proto] = type;
215 else
216 err = -EEXIST;
217 xfrm_state_unlock_afinfo(afinfo);
218 return err;
219}
220EXPORT_SYMBOL(xfrm_register_type);
221
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800222int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700223{
224 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800225 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700226 int err = 0;
227
228 if (unlikely(afinfo == NULL))
229 return -EAFNOSUPPORT;
230 typemap = afinfo->type_map;
231
232 if (unlikely(typemap[type->proto] != type))
233 err = -ENOENT;
234 else
235 typemap[type->proto] = NULL;
236 xfrm_state_unlock_afinfo(afinfo);
237 return err;
238}
239EXPORT_SYMBOL(xfrm_unregister_type);
240
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800241static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700242{
243 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800244 const struct xfrm_type **typemap;
245 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700246 int modload_attempted = 0;
247
248retry:
249 afinfo = xfrm_state_get_afinfo(family);
250 if (unlikely(afinfo == NULL))
251 return NULL;
252 typemap = afinfo->type_map;
253
254 type = typemap[proto];
255 if (unlikely(type && !try_module_get(type->owner)))
256 type = NULL;
257 if (!type && !modload_attempted) {
258 xfrm_state_put_afinfo(afinfo);
259 request_module("xfrm-type-%d-%d", family, proto);
260 modload_attempted = 1;
261 goto retry;
262 }
263
264 xfrm_state_put_afinfo(afinfo);
265 return type;
266}
267
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800268static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700269{
270 module_put(type->owner);
271}
272
273int xfrm_register_mode(struct xfrm_mode *mode, int family)
274{
275 struct xfrm_state_afinfo *afinfo;
276 struct xfrm_mode **modemap;
277 int err;
278
279 if (unlikely(mode->encap >= XFRM_MODE_MAX))
280 return -EINVAL;
281
282 afinfo = xfrm_state_lock_afinfo(family);
283 if (unlikely(afinfo == NULL))
284 return -EAFNOSUPPORT;
285
286 err = -EEXIST;
287 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700288 if (modemap[mode->encap])
289 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700290
Herbert Xu17c2a422007-10-17 21:33:12 -0700291 err = -ENOENT;
292 if (!try_module_get(afinfo->owner))
293 goto out;
294
295 mode->afinfo = afinfo;
296 modemap[mode->encap] = mode;
297 err = 0;
298
299out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700300 xfrm_state_unlock_afinfo(afinfo);
301 return err;
302}
303EXPORT_SYMBOL(xfrm_register_mode);
304
305int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
306{
307 struct xfrm_state_afinfo *afinfo;
308 struct xfrm_mode **modemap;
309 int err;
310
311 if (unlikely(mode->encap >= XFRM_MODE_MAX))
312 return -EINVAL;
313
314 afinfo = xfrm_state_lock_afinfo(family);
315 if (unlikely(afinfo == NULL))
316 return -EAFNOSUPPORT;
317
318 err = -ENOENT;
319 modemap = afinfo->mode_map;
320 if (likely(modemap[mode->encap] == mode)) {
321 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700322 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700323 err = 0;
324 }
325
326 xfrm_state_unlock_afinfo(afinfo);
327 return err;
328}
329EXPORT_SYMBOL(xfrm_unregister_mode);
330
331static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
332{
333 struct xfrm_state_afinfo *afinfo;
334 struct xfrm_mode *mode;
335 int modload_attempted = 0;
336
337 if (unlikely(encap >= XFRM_MODE_MAX))
338 return NULL;
339
340retry:
341 afinfo = xfrm_state_get_afinfo(family);
342 if (unlikely(afinfo == NULL))
343 return NULL;
344
345 mode = afinfo->mode_map[encap];
346 if (unlikely(mode && !try_module_get(mode->owner)))
347 mode = NULL;
348 if (!mode && !modload_attempted) {
349 xfrm_state_put_afinfo(afinfo);
350 request_module("xfrm-mode-%d-%d", family, encap);
351 modload_attempted = 1;
352 goto retry;
353 }
354
355 xfrm_state_put_afinfo(afinfo);
356 return mode;
357}
358
359static void xfrm_put_mode(struct xfrm_mode *mode)
360{
361 module_put(mode->owner);
362}
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364static void xfrm_state_gc_destroy(struct xfrm_state *x)
365{
David S. Millera47f0ce2006-08-24 03:54:22 -0700366 del_timer_sync(&x->timer);
367 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800368 kfree(x->aalg);
369 kfree(x->ealg);
370 kfree(x->calg);
371 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700372 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700373 if (x->inner_mode)
374 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700375 if (x->inner_mode_iaf)
376 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700377 if (x->outer_mode)
378 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (x->type) {
380 x->type->destructor(x);
381 xfrm_put_type(x->type);
382 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800383 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 kfree(x);
385}
386
Alexey Dobriyanc7837142008-11-25 17:20:36 -0800387static void xfrm_state_gc_task(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
Alexey Dobriyanc7837142008-11-25 17:20:36 -0800389 struct net *net = container_of(work, struct net, xfrm.state_gc_work);
Herbert Xu12a169e2008-10-01 07:03:24 -0700390 struct xfrm_state *x;
391 struct hlist_node *entry, *tmp;
392 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 spin_lock_bh(&xfrm_state_gc_lock);
Alexey Dobriyanc7837142008-11-25 17:20:36 -0800395 hlist_move_list(&net->xfrm.state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 spin_unlock_bh(&xfrm_state_gc_lock);
397
Herbert Xu12a169e2008-10-01 07:03:24 -0700398 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700400
Alexey Dobriyan50a30652008-11-25 17:21:01 -0800401 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}
403
404static inline unsigned long make_jiffies(long secs)
405{
406 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
407 return MAX_SCHEDULE_TIMEOUT-1;
408 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900409 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
412static void xfrm_timer_handler(unsigned long data)
413{
414 struct xfrm_state *x = (struct xfrm_state*)data;
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800415 struct net *net = xs_net(x);
James Morris9d729f72007-03-04 16:12:44 -0800416 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 long next = LONG_MAX;
418 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600419 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 spin_lock(&x->lock);
422 if (x->km.state == XFRM_STATE_DEAD)
423 goto out;
424 if (x->km.state == XFRM_STATE_EXPIRED)
425 goto expired;
426 if (x->lft.hard_add_expires_seconds) {
427 long tmo = x->lft.hard_add_expires_seconds +
428 x->curlft.add_time - now;
429 if (tmo <= 0)
430 goto expired;
431 if (tmo < next)
432 next = tmo;
433 }
434 if (x->lft.hard_use_expires_seconds) {
435 long tmo = x->lft.hard_use_expires_seconds +
436 (x->curlft.use_time ? : now) - now;
437 if (tmo <= 0)
438 goto expired;
439 if (tmo < next)
440 next = tmo;
441 }
442 if (x->km.dying)
443 goto resched;
444 if (x->lft.soft_add_expires_seconds) {
445 long tmo = x->lft.soft_add_expires_seconds +
446 x->curlft.add_time - now;
447 if (tmo <= 0)
448 warn = 1;
449 else if (tmo < next)
450 next = tmo;
451 }
452 if (x->lft.soft_use_expires_seconds) {
453 long tmo = x->lft.soft_use_expires_seconds +
454 (x->curlft.use_time ? : now) - now;
455 if (tmo <= 0)
456 warn = 1;
457 else if (tmo < next)
458 next = tmo;
459 }
460
Herbert Xu4666faa2005-06-18 22:43:22 -0700461 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (warn)
Jamal Hadi Salim53bc6b4d2006-03-20 19:17:03 -0800463 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700465 if (next != LONG_MAX)
466 mod_timer(&x->timer, jiffies + make_jiffies(next));
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 goto out;
469
470expired:
471 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
472 x->km.state = XFRM_STATE_EXPIRED;
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800473 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 next = 2;
475 goto resched;
476 }
Joy Latten161a09e2006-11-27 13:11:54 -0600477
478 err = __xfrm_state_delete(x);
479 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b4d2006-03-20 19:17:03 -0800480 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Joy Lattenab5f5e82007-09-17 11:51:22 -0700482 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400483 audit_get_loginuid(current),
484 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486out:
487 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
David S. Miller0ac84752006-03-20 19:18:23 -0800490static void xfrm_replay_timer_handler(unsigned long data);
491
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800492struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
494 struct xfrm_state *x;
495
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700496 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800499 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 atomic_set(&x->refcnt, 1);
501 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700502 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700503 INIT_HLIST_NODE(&x->bydst);
504 INIT_HLIST_NODE(&x->bysrc);
505 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800506 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
507 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
508 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800509 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 x->lft.soft_byte_limit = XFRM_INF;
511 x->lft.soft_packet_limit = XFRM_INF;
512 x->lft.hard_byte_limit = XFRM_INF;
513 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800514 x->replay_maxage = 0;
515 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700516 x->inner_mode = NULL;
517 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 spin_lock_init(&x->lock);
519 }
520 return x;
521}
522EXPORT_SYMBOL(xfrm_state_alloc);
523
524void __xfrm_state_destroy(struct xfrm_state *x)
525{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800526 struct net *net = xs_net(x);
527
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700528 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 spin_lock_bh(&xfrm_state_gc_lock);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800531 hlist_add_head(&x->gclist, &net->xfrm.state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 spin_unlock_bh(&xfrm_state_gc_lock);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800533 schedule_work(&net->xfrm.state_gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535EXPORT_SYMBOL(__xfrm_state_destroy);
536
Jamal Hadi Salim53bc6b4d2006-03-20 19:17:03 -0800537int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800539 struct net *net = xs_net(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700540 int err = -ESRCH;
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (x->km.state != XFRM_STATE_DEAD) {
543 x->km.state = XFRM_STATE_DEAD;
544 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700545 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700546 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700547 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700548 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700549 hlist_del(&x->byspi);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800550 net->xfrm.state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 /* All xfrm_state objects are created by xfrm_state_alloc.
554 * The xfrm_state_alloc call gives a reference, and that
555 * is what we are dropping here.
556 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800557 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700558 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700560
561 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
Jamal Hadi Salim53bc6b4d2006-03-20 19:17:03 -0800563EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700565int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567 int err;
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700570 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700572
573 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575EXPORT_SYMBOL(xfrm_state_delete);
576
Joy Latten4aa2e622007-06-04 19:05:57 -0400577#ifdef CONFIG_SECURITY_NETWORK_XFRM
578static inline int
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800579xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Joy Latten4aa2e622007-06-04 19:05:57 -0400581 int i, err = 0;
582
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800583 for (i = 0; i <= net->xfrm.state_hmask; i++) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400584 struct hlist_node *entry;
585 struct xfrm_state *x;
586
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800587 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
Joy Latten4aa2e622007-06-04 19:05:57 -0400588 if (xfrm_id_proto_match(x->id.proto, proto) &&
589 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700590 xfrm_audit_state_delete(x, 0,
591 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400592 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700593 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400594 return err;
595 }
596 }
597 }
598
599 return err;
600}
601#else
602static inline int
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800603xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
Joy Latten4aa2e622007-06-04 19:05:57 -0400604{
605 return 0;
606}
607#endif
608
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800609int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
Joy Latten4aa2e622007-06-04 19:05:57 -0400610{
611 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800614 err = xfrm_state_flush_secctx_check(net, proto, audit_info);
Joy Latten4aa2e622007-06-04 19:05:57 -0400615 if (err)
616 goto out;
617
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800618 for (i = 0; i <= net->xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700619 struct hlist_node *entry;
620 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621restart:
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800622 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700624 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 xfrm_state_hold(x);
626 spin_unlock_bh(&xfrm_state_lock);
627
Joy Latten161a09e2006-11-27 13:11:54 -0600628 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700629 xfrm_audit_state_delete(x, err ? 0 : 1,
630 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400631 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700632 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 xfrm_state_put(x);
634
635 spin_lock_bh(&xfrm_state_lock);
636 goto restart;
637 }
638 }
639 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400640 err = 0;
641
642out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 spin_unlock_bh(&xfrm_state_lock);
Alexey Dobriyan0e602452008-11-25 17:30:18 -0800644 wake_up(&net->xfrm.km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400645 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647EXPORT_SYMBOL(xfrm_state_flush);
648
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700649void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700650{
651 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800652 si->sadcnt = init_net.xfrm.state_num;
Alexey Dobriyan529983e2008-11-25 17:18:12 -0800653 si->sadhcnt = init_net.xfrm.state_hmask;
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700654 si->sadhmcnt = xfrm_state_hashmax;
655 spin_unlock_bh(&xfrm_state_lock);
656}
657EXPORT_SYMBOL(xfrm_sad_getinfo);
658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659static int
660xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
661 struct xfrm_tmpl *tmpl,
662 xfrm_address_t *daddr, xfrm_address_t *saddr,
663 unsigned short family)
664{
665 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
666 if (!afinfo)
667 return -1;
668 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
669 xfrm_state_put_afinfo(afinfo);
670 return 0;
671}
672
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800673static 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 -0700674{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800675 unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700676 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700677 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700678
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800679 hlist_for_each_entry(x, entry, net->xfrm.state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700680 if (x->props.family != family ||
681 x->id.spi != spi ||
682 x->id.proto != proto)
683 continue;
684
685 switch (family) {
686 case AF_INET:
687 if (x->id.daddr.a4 != daddr->a4)
688 continue;
689 break;
690 case AF_INET6:
691 if (!ipv6_addr_equal((struct in6_addr *)daddr,
692 (struct in6_addr *)
693 x->id.daddr.a6))
694 continue;
695 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700696 }
David S. Milleredcd5822006-08-24 00:42:45 -0700697
698 xfrm_state_hold(x);
699 return x;
700 }
701
702 return NULL;
703}
704
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800705static 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 -0700706{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800707 unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700708 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700709 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700710
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800711 hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700712 if (x->props.family != family ||
713 x->id.proto != proto)
714 continue;
715
716 switch (family) {
717 case AF_INET:
718 if (x->id.daddr.a4 != daddr->a4 ||
719 x->props.saddr.a4 != saddr->a4)
720 continue;
721 break;
722 case AF_INET6:
723 if (!ipv6_addr_equal((struct in6_addr *)daddr,
724 (struct in6_addr *)
725 x->id.daddr.a6) ||
726 !ipv6_addr_equal((struct in6_addr *)saddr,
727 (struct in6_addr *)
728 x->props.saddr.a6))
729 continue;
730 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700731 }
David S. Milleredcd5822006-08-24 00:42:45 -0700732
733 xfrm_state_hold(x);
734 return x;
735 }
736
737 return NULL;
738}
739
740static inline struct xfrm_state *
741__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
742{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800743 struct net *net = xs_net(x);
744
David S. Milleredcd5822006-08-24 00:42:45 -0700745 if (use_spi)
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800746 return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi,
David S. Milleredcd5822006-08-24 00:42:45 -0700747 x->id.proto, family);
748 else
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800749 return __xfrm_state_lookup_byaddr(net, &x->id.daddr,
David S. Milleredcd5822006-08-24 00:42:45 -0700750 &x->props.saddr,
751 x->id.proto, family);
752}
753
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800754static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700755{
756 if (have_hash_collision &&
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800757 (net->xfrm.state_hmask + 1) < xfrm_state_hashmax &&
758 net->xfrm.state_num > net->xfrm.state_hmask)
759 schedule_work(&net->xfrm.state_hash_work);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700760}
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900763xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 struct flowi *fl, struct xfrm_tmpl *tmpl,
765 struct xfrm_policy *pol, int *err,
766 unsigned short family)
767{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800768 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700769 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700770 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 int acquire_in_progress = 0;
772 int error = 0;
773 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900774
David S. Miller37b08e32008-09-02 20:14:15 -0700775 to_put = NULL;
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -0800778 h = xfrm_dst_hash(&init_net, daddr, saddr, tmpl->reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800779 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (x->props.family == family &&
781 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700782 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 xfrm_state_addr_check(x, daddr, saddr, family) &&
784 tmpl->mode == x->props.mode &&
785 tmpl->id.proto == x->id.proto &&
786 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
787 /* Resolution logic:
788 1. There is a valid state with matching selector.
789 Done.
790 2. Valid state with inappropriate selector. Skip.
791
792 Entering area of "sysdeps".
793
794 3. If state is not valid, selector is temporary,
795 it selects only session which triggered
796 previous resolution. Key manager will do
797 something to install a state with proper
798 selector.
799 */
800 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700801 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700802 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 continue;
804 if (!best ||
805 best->km.dying > x->km.dying ||
806 (best->km.dying == x->km.dying &&
807 best->curlft.add_time < x->curlft.add_time))
808 best = x;
809 } else if (x->km.state == XFRM_STATE_ACQ) {
810 acquire_in_progress = 1;
811 } else if (x->km.state == XFRM_STATE_ERROR ||
812 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700813 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700814 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 error = -ESRCH;
816 }
817 }
818 }
819
820 x = best;
821 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700822 if (tmpl->id.spi &&
Alexey Dobriyan221df1e2008-11-25 17:30:50 -0800823 (x0 = __xfrm_state_lookup(&init_net, daddr, tmpl->id.spi,
David S. Milleredcd5822006-08-24 00:42:45 -0700824 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700825 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 error = -EEXIST;
827 goto out;
828 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800829 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 if (x == NULL) {
831 error = -ENOMEM;
832 goto out;
833 }
834 /* Initialize temporary selector matching only
835 * to current session. */
836 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
837
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700838 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
839 if (error) {
840 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700841 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700842 x = NULL;
843 goto out;
844 }
845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (km_query(x, tmpl, pol) == 0) {
847 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -0800848 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800849 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -0800850 h = xfrm_src_hash(&init_net, daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -0800851 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (x->id.spi) {
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -0800853 h = xfrm_spi_hash(&init_net, &x->id.daddr, x->id.spi, x->id.proto, family);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -0800854 hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
David S. Miller01e67d02007-05-25 00:41:38 -0700856 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
857 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 add_timer(&x->timer);
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -0800859 init_net.xfrm.state_num++;
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800860 xfrm_hash_grow_check(&init_net, x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 } else {
862 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700863 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 x = NULL;
865 error = -ESRCH;
866 }
867 }
868out:
869 if (x)
870 xfrm_state_hold(x);
871 else
872 *err = acquire_in_progress ? -EAGAIN : error;
873 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700874 if (to_put)
875 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 return x;
877}
878
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700879struct xfrm_state *
880xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
881 unsigned short family, u8 mode, u8 proto, u32 reqid)
882{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800883 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700884 struct xfrm_state *rx = NULL, *x = NULL;
885 struct hlist_node *entry;
886
887 spin_lock(&xfrm_state_lock);
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -0800888 h = xfrm_dst_hash(&init_net, daddr, saddr, reqid, family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800889 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700890 if (x->props.family == family &&
891 x->props.reqid == reqid &&
892 !(x->props.flags & XFRM_STATE_WILDRECV) &&
893 xfrm_state_addr_check(x, daddr, saddr, family) &&
894 mode == x->props.mode &&
895 proto == x->id.proto &&
896 x->km.state == XFRM_STATE_VALID) {
897 rx = x;
898 break;
899 }
900 }
901
902 if (rx)
903 xfrm_state_hold(rx);
904 spin_unlock(&xfrm_state_lock);
905
906
907 return rx;
908}
909EXPORT_SYMBOL(xfrm_stateonly_find);
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911static void __xfrm_state_insert(struct xfrm_state *x)
912{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800913 struct net *net = xs_net(x);
David S. Millera624c102006-08-24 03:24:33 -0700914 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
David S. Miller9d4a7062006-08-24 03:18:09 -0700916 x->genid = ++xfrm_state_genid;
917
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800918 list_add(&x->km.all, &net->xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800919
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800920 h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
David S. Millerc1969f22006-08-24 04:00:03 -0700921 x->props.reqid, x->props.family);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800922 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800924 h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
925 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700927 if (x->id.spi) {
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800928 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700929 x->props.family);
930
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800931 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700932 }
933
David S. Millera47f0ce2006-08-24 03:54:22 -0700934 mod_timer(&x->timer, jiffies + HZ);
935 if (x->replay_maxage)
936 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800937
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800938 wake_up(&net->xfrm.km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700939
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800940 net->xfrm.state_num++;
David S. Millerf034b5d2006-08-24 03:08:07 -0700941
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800942 xfrm_hash_grow_check(net, x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943}
944
David S. Millerc7f5ea32006-08-24 03:29:04 -0700945/* xfrm_state_lock is held */
946static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
947{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800948 struct net *net = xs_net(xnew);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700949 unsigned short family = xnew->props.family;
950 u32 reqid = xnew->props.reqid;
951 struct xfrm_state *x;
952 struct hlist_node *entry;
953 unsigned int h;
954
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800955 h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
956 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700957 if (x->props.family == family &&
958 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700959 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
960 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700961 x->genid = xfrm_state_genid;
962 }
963}
964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965void xfrm_state_insert(struct xfrm_state *x)
966{
967 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700968 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 __xfrm_state_insert(x);
970 spin_unlock_bh(&xfrm_state_lock);
971}
972EXPORT_SYMBOL(xfrm_state_insert);
973
David S. Miller27708342006-08-24 00:13:10 -0700974/* xfrm_state_lock is held */
975static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
976{
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -0800977 unsigned int h = xfrm_dst_hash(&init_net, daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700978 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700979 struct xfrm_state *x;
980
Alexey Dobriyan73d189d2008-11-25 17:16:58 -0800981 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700982 if (x->props.reqid != reqid ||
983 x->props.mode != mode ||
984 x->props.family != family ||
985 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700986 x->id.spi != 0 ||
987 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700988 continue;
989
990 switch (family) {
991 case AF_INET:
992 if (x->id.daddr.a4 != daddr->a4 ||
993 x->props.saddr.a4 != saddr->a4)
994 continue;
995 break;
996 case AF_INET6:
997 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
998 (struct in6_addr *)daddr) ||
999 !ipv6_addr_equal((struct in6_addr *)
1000 x->props.saddr.a6,
1001 (struct in6_addr *)saddr))
1002 continue;
1003 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001004 }
David S. Miller27708342006-08-24 00:13:10 -07001005
1006 xfrm_state_hold(x);
1007 return x;
1008 }
1009
1010 if (!create)
1011 return NULL;
1012
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001013 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001014 if (likely(x)) {
1015 switch (family) {
1016 case AF_INET:
1017 x->sel.daddr.a4 = daddr->a4;
1018 x->sel.saddr.a4 = saddr->a4;
1019 x->sel.prefixlen_d = 32;
1020 x->sel.prefixlen_s = 32;
1021 x->props.saddr.a4 = saddr->a4;
1022 x->id.daddr.a4 = daddr->a4;
1023 break;
1024
1025 case AF_INET6:
1026 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1027 (struct in6_addr *)daddr);
1028 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1029 (struct in6_addr *)saddr);
1030 x->sel.prefixlen_d = 128;
1031 x->sel.prefixlen_s = 128;
1032 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1033 (struct in6_addr *)saddr);
1034 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1035 (struct in6_addr *)daddr);
1036 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001037 }
David S. Miller27708342006-08-24 00:13:10 -07001038
1039 x->km.state = XFRM_STATE_ACQ;
1040 x->id.proto = proto;
1041 x->props.family = family;
1042 x->props.mode = mode;
1043 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001044 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001045 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001046 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001047 add_timer(&x->timer);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001048 list_add(&x->km.all, &init_net.xfrm.state_all);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001049 hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h);
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -08001050 h = xfrm_src_hash(&init_net, daddr, saddr, family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001051 hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001052
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08001053 init_net.xfrm.state_num++;
David S. Miller918049f2006-10-12 22:03:24 -07001054
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001055 xfrm_hash_grow_check(&init_net, x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001056 }
1057
1058 return x;
1059}
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1062
1063int xfrm_state_add(struct xfrm_state *x)
1064{
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) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 x1 = __xfrm_find_acq_byseq(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)
David S. Miller27708342006-08-24 00:13:10 -07001094 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1095 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 Salim53bc6b4d2006-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 *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001393xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1394 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);
David S. Miller27708342006-08-24 00:13:10 -07001400 x = __find_acq_core(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
1447static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1448{
1449 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Alexey Dobriyan529983e2008-11-25 17:18:12 -08001451 for (i = 0; i <= init_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 Dobriyan73d189d2008-11-25 17:16:58 -08001455 hlist_for_each_entry(x, entry, init_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
1466struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1467{
1468 struct xfrm_state *x;
1469
1470 spin_lock_bh(&xfrm_state_lock);
1471 x = __xfrm_find_acq_byseq(seq);
1472 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
Timo Teras4c563f72008-02-28 21:31:08 -08001544int xfrm_state_walk(struct xfrm_state_walk *walk,
1545 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 Dobriyan9d4139c2008-11-25 17:16:11 -08001557 x = list_first_entry(&init_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 Dobriyan9d4139c2008-11-25 17:16:11 -08001560 list_for_each_entry_from(x, &init_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) {
1659 if (xfrm_aevent_is_on())
1660 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
1715 if (xfrm_aevent_is_on())
1716 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 Salim53bc6b4d2006-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 Xubf08867f92005-06-18 22:44:00 -07001751 c.data.hard = hard;
Jamal Hadi Salim53bc6b4d2006-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 Salim53bc6b4d2006-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 Xubf08867f92005-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
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001836int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1837{
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) {
1845 ret = km->report(proto, sel, addr);
1846 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 */