blob: 0d974fc9dd6c3641ccd270aa024e9e1f781fa7a6 [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 Salim53bc6b42006-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 Salim53bc6b42006-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 Salim53bc6b42006-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 Salim53bc6b42006-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 Salim53bc6b42006-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 Salim53bc6b42006-03-20 19:17:03 -0800563EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700565int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700567 int err;
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700570 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700572
573 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575EXPORT_SYMBOL(xfrm_state_delete);
576
Joy Latten4aa2e622007-06-04 19:05:57 -0400577#ifdef CONFIG_SECURITY_NETWORK_XFRM
578static inline int
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{
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800768 struct net *net = xp_net(pol);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800769 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700770 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700771 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 int acquire_in_progress = 0;
773 int error = 0;
774 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900775
David S. Miller37b08e32008-09-02 20:14:15 -0700776 to_put = NULL;
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800779 h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family);
780 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (x->props.family == family &&
782 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700783 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 xfrm_state_addr_check(x, daddr, saddr, family) &&
785 tmpl->mode == x->props.mode &&
786 tmpl->id.proto == x->id.proto &&
787 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
788 /* Resolution logic:
789 1. There is a valid state with matching selector.
790 Done.
791 2. Valid state with inappropriate selector. Skip.
792
793 Entering area of "sysdeps".
794
795 3. If state is not valid, selector is temporary,
796 it selects only session which triggered
797 previous resolution. Key manager will do
798 something to install a state with proper
799 selector.
800 */
801 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700802 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700803 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 continue;
805 if (!best ||
806 best->km.dying > x->km.dying ||
807 (best->km.dying == x->km.dying &&
808 best->curlft.add_time < x->curlft.add_time))
809 best = x;
810 } else if (x->km.state == XFRM_STATE_ACQ) {
811 acquire_in_progress = 1;
812 } else if (x->km.state == XFRM_STATE_ERROR ||
813 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700814 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700815 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 error = -ESRCH;
817 }
818 }
819 }
820
821 x = best;
822 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700823 if (tmpl->id.spi &&
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800824 (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi,
David S. Milleredcd5822006-08-24 00:42:45 -0700825 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700826 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 error = -EEXIST;
828 goto out;
829 }
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800830 x = xfrm_state_alloc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (x == NULL) {
832 error = -ENOMEM;
833 goto out;
834 }
835 /* Initialize temporary selector matching only
836 * to current session. */
837 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
838
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700839 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
840 if (error) {
841 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700842 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700843 x = NULL;
844 goto out;
845 }
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (km_query(x, tmpl, pol) == 0) {
848 x->km.state = XFRM_STATE_ACQ;
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800849 list_add(&x->km.all, &net->xfrm.state_all);
850 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
851 h = xfrm_src_hash(net, daddr, saddr, family);
852 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 if (x->id.spi) {
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800854 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family);
855 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
David S. Miller01e67d02007-05-25 00:41:38 -0700857 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
858 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 add_timer(&x->timer);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800860 net->xfrm.state_num++;
861 xfrm_hash_grow_check(net, x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 } else {
863 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700864 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 x = NULL;
866 error = -ESRCH;
867 }
868 }
869out:
870 if (x)
871 xfrm_state_hold(x);
872 else
873 *err = acquire_in_progress ? -EAGAIN : error;
874 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700875 if (to_put)
876 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return x;
878}
879
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700880struct xfrm_state *
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800881xfrm_stateonly_find(struct net *net,
882 xfrm_address_t *daddr, xfrm_address_t *saddr,
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700883 unsigned short family, u8 mode, u8 proto, u32 reqid)
884{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800885 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700886 struct xfrm_state *rx = NULL, *x = NULL;
887 struct hlist_node *entry;
888
889 spin_lock(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800890 h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
891 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700892 if (x->props.family == family &&
893 x->props.reqid == reqid &&
894 !(x->props.flags & XFRM_STATE_WILDRECV) &&
895 xfrm_state_addr_check(x, daddr, saddr, family) &&
896 mode == x->props.mode &&
897 proto == x->id.proto &&
898 x->km.state == XFRM_STATE_VALID) {
899 rx = x;
900 break;
901 }
902 }
903
904 if (rx)
905 xfrm_state_hold(rx);
906 spin_unlock(&xfrm_state_lock);
907
908
909 return rx;
910}
911EXPORT_SYMBOL(xfrm_stateonly_find);
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913static void __xfrm_state_insert(struct xfrm_state *x)
914{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800915 struct net *net = xs_net(x);
David S. Millera624c102006-08-24 03:24:33 -0700916 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
David S. Miller9d4a7062006-08-24 03:18:09 -0700918 x->genid = ++xfrm_state_genid;
919
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800920 list_add(&x->km.all, &net->xfrm.state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800921
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800922 h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
David S. Millerc1969f22006-08-24 04:00:03 -0700923 x->props.reqid, x->props.family);
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800924 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800926 h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
927 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700929 if (x->id.spi) {
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800930 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700931 x->props.family);
932
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800933 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700934 }
935
David S. Millera47f0ce2006-08-24 03:54:22 -0700936 mod_timer(&x->timer, jiffies + HZ);
937 if (x->replay_maxage)
938 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800939
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800940 wake_up(&net->xfrm.km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700941
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800942 net->xfrm.state_num++;
David S. Millerf034b5d2006-08-24 03:08:07 -0700943
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800944 xfrm_hash_grow_check(net, x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
David S. Millerc7f5ea32006-08-24 03:29:04 -0700947/* xfrm_state_lock is held */
948static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
949{
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800950 struct net *net = xs_net(xnew);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700951 unsigned short family = xnew->props.family;
952 u32 reqid = xnew->props.reqid;
953 struct xfrm_state *x;
954 struct hlist_node *entry;
955 unsigned int h;
956
Alexey Dobriyan98806f72008-11-25 17:29:47 -0800957 h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
958 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
David S. Millerc7f5ea32006-08-24 03:29:04 -0700959 if (x->props.family == family &&
960 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700961 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
962 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700963 x->genid = xfrm_state_genid;
964 }
965}
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967void xfrm_state_insert(struct xfrm_state *x)
968{
969 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700970 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 __xfrm_state_insert(x);
972 spin_unlock_bh(&xfrm_state_lock);
973}
974EXPORT_SYMBOL(xfrm_state_insert);
975
David S. Miller27708342006-08-24 00:13:10 -0700976/* xfrm_state_lock is held */
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800977static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
David S. Miller27708342006-08-24 00:13:10 -0700978{
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800979 unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700980 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700981 struct xfrm_state *x;
982
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -0800983 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700984 if (x->props.reqid != reqid ||
985 x->props.mode != mode ||
986 x->props.family != family ||
987 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700988 x->id.spi != 0 ||
989 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700990 continue;
991
992 switch (family) {
993 case AF_INET:
994 if (x->id.daddr.a4 != daddr->a4 ||
995 x->props.saddr.a4 != saddr->a4)
996 continue;
997 break;
998 case AF_INET6:
999 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
1000 (struct in6_addr *)daddr) ||
1001 !ipv6_addr_equal((struct in6_addr *)
1002 x->props.saddr.a6,
1003 (struct in6_addr *)saddr))
1004 continue;
1005 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001006 }
David S. Miller27708342006-08-24 00:13:10 -07001007
1008 xfrm_state_hold(x);
1009 return x;
1010 }
1011
1012 if (!create)
1013 return NULL;
1014
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001015 x = xfrm_state_alloc(net);
David S. Miller27708342006-08-24 00:13:10 -07001016 if (likely(x)) {
1017 switch (family) {
1018 case AF_INET:
1019 x->sel.daddr.a4 = daddr->a4;
1020 x->sel.saddr.a4 = saddr->a4;
1021 x->sel.prefixlen_d = 32;
1022 x->sel.prefixlen_s = 32;
1023 x->props.saddr.a4 = saddr->a4;
1024 x->id.daddr.a4 = daddr->a4;
1025 break;
1026
1027 case AF_INET6:
1028 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1029 (struct in6_addr *)daddr);
1030 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1031 (struct in6_addr *)saddr);
1032 x->sel.prefixlen_d = 128;
1033 x->sel.prefixlen_s = 128;
1034 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1035 (struct in6_addr *)saddr);
1036 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1037 (struct in6_addr *)daddr);
1038 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001039 }
David S. Miller27708342006-08-24 00:13:10 -07001040
1041 x->km.state = XFRM_STATE_ACQ;
1042 x->id.proto = proto;
1043 x->props.family = family;
1044 x->props.mode = mode;
1045 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001046 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001047 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001048 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001049 add_timer(&x->timer);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001050 list_add(&x->km.all, &net->xfrm.state_all);
1051 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
1052 h = xfrm_src_hash(net, daddr, saddr, family);
1053 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001054
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001055 net->xfrm.state_num++;
David S. Miller918049f2006-10-12 22:03:24 -07001056
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001057 xfrm_hash_grow_check(net, x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001058 }
1059
1060 return x;
1061}
1062
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001063static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065int xfrm_state_add(struct xfrm_state *x)
1066{
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001067 struct net *net = xs_net(x);
David S. Miller37b08e32008-09-02 20:14:15 -07001068 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 int family;
1070 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001071 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
David S. Miller37b08e32008-09-02 20:14:15 -07001075 to_put = NULL;
1076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 spin_lock_bh(&xfrm_state_lock);
1078
David S. Milleredcd5822006-08-24 00:42:45 -07001079 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001081 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 x1 = NULL;
1083 err = -EEXIST;
1084 goto out;
1085 }
1086
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001087 if (use_spi && x->km.seq) {
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001088 x1 = __xfrm_find_acq_byseq(net, x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001089 if (x1 && ((x1->id.proto != x->id.proto) ||
1090 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001091 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 x1 = NULL;
1093 }
1094 }
1095
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001096 if (use_spi && !x1)
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001097 x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid,
David S. Miller27708342006-08-24 00:13:10 -07001098 x->id.proto,
1099 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
David S. Millerc7f5ea32006-08-24 03:29:04 -07001101 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 __xfrm_state_insert(x);
1103 err = 0;
1104
1105out:
1106 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 if (x1) {
1109 xfrm_state_delete(x1);
1110 xfrm_state_put(x1);
1111 }
1112
David S. Miller37b08e32008-09-02 20:14:15 -07001113 if (to_put)
1114 xfrm_state_put(to_put);
1115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return err;
1117}
1118EXPORT_SYMBOL(xfrm_state_add);
1119
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001120#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001121static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001122{
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001123 struct net *net = xs_net(orig);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001124 int err = -ENOMEM;
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001125 struct xfrm_state *x = xfrm_state_alloc(net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001126 if (!x)
1127 goto error;
1128
1129 memcpy(&x->id, &orig->id, sizeof(x->id));
1130 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1131 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1132 x->props.mode = orig->props.mode;
1133 x->props.replay_window = orig->props.replay_window;
1134 x->props.reqid = orig->props.reqid;
1135 x->props.family = orig->props.family;
1136 x->props.saddr = orig->props.saddr;
1137
1138 if (orig->aalg) {
1139 x->aalg = xfrm_algo_clone(orig->aalg);
1140 if (!x->aalg)
1141 goto error;
1142 }
1143 x->props.aalgo = orig->props.aalgo;
1144
1145 if (orig->ealg) {
1146 x->ealg = xfrm_algo_clone(orig->ealg);
1147 if (!x->ealg)
1148 goto error;
1149 }
1150 x->props.ealgo = orig->props.ealgo;
1151
1152 if (orig->calg) {
1153 x->calg = xfrm_algo_clone(orig->calg);
1154 if (!x->calg)
1155 goto error;
1156 }
1157 x->props.calgo = orig->props.calgo;
1158
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001159 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001160 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1161 if (!x->encap)
1162 goto error;
1163 }
1164
1165 if (orig->coaddr) {
1166 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1167 GFP_KERNEL);
1168 if (!x->coaddr)
1169 goto error;
1170 }
1171
1172 err = xfrm_init_state(x);
1173 if (err)
1174 goto error;
1175
1176 x->props.flags = orig->props.flags;
1177
1178 x->curlft.add_time = orig->curlft.add_time;
1179 x->km.state = orig->km.state;
1180 x->km.seq = orig->km.seq;
1181
1182 return x;
1183
1184 error:
1185 if (errp)
1186 *errp = err;
1187 if (x) {
1188 kfree(x->aalg);
1189 kfree(x->ealg);
1190 kfree(x->calg);
1191 kfree(x->encap);
1192 kfree(x->coaddr);
1193 }
1194 kfree(x);
1195 return NULL;
1196}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001197
1198/* xfrm_state_lock is held */
1199struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1200{
1201 unsigned int h;
1202 struct xfrm_state *x;
1203 struct hlist_node *entry;
1204
1205 if (m->reqid) {
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -08001206 h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr,
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001207 m->reqid, m->old_family);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08001208 hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001209 if (x->props.mode != m->mode ||
1210 x->id.proto != m->proto)
1211 continue;
1212 if (m->reqid && x->props.reqid != m->reqid)
1213 continue;
1214 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1215 m->old_family) ||
1216 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1217 m->old_family))
1218 continue;
1219 xfrm_state_hold(x);
1220 return x;
1221 }
1222 } else {
Alexey Dobriyan64d0cd02008-11-25 17:29:21 -08001223 h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr,
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001224 m->old_family);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08001225 hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001226 if (x->props.mode != m->mode ||
1227 x->id.proto != m->proto)
1228 continue;
1229 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1230 m->old_family) ||
1231 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1232 m->old_family))
1233 continue;
1234 xfrm_state_hold(x);
1235 return x;
1236 }
1237 }
1238
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001239 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001240}
1241EXPORT_SYMBOL(xfrm_migrate_state_find);
1242
1243struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1244 struct xfrm_migrate *m)
1245{
1246 struct xfrm_state *xc;
1247 int err;
1248
1249 xc = xfrm_state_clone(x, &err);
1250 if (!xc)
1251 return NULL;
1252
1253 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1254 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1255
1256 /* add state */
1257 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1258 /* a care is needed when the destination address of the
1259 state is to be updated as it is a part of triplet */
1260 xfrm_state_insert(xc);
1261 } else {
1262 if ((err = xfrm_state_add(xc)) < 0)
1263 goto error;
1264 }
1265
1266 return xc;
1267error:
1268 kfree(xc);
1269 return NULL;
1270}
1271EXPORT_SYMBOL(xfrm_state_migrate);
1272#endif
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274int xfrm_state_update(struct xfrm_state *x)
1275{
David S. Miller37b08e32008-09-02 20:14:15 -07001276 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001278 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
David S. Miller37b08e32008-09-02 20:14:15 -07001280 to_put = NULL;
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001283 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285 err = -ESRCH;
1286 if (!x1)
1287 goto out;
1288
1289 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001290 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 err = -EEXIST;
1292 goto out;
1293 }
1294
1295 if (x1->km.state == XFRM_STATE_ACQ) {
1296 __xfrm_state_insert(x);
1297 x = NULL;
1298 }
1299 err = 0;
1300
1301out:
1302 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
David S. Miller37b08e32008-09-02 20:14:15 -07001304 if (to_put)
1305 xfrm_state_put(to_put);
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (err)
1308 return err;
1309
1310 if (!x) {
1311 xfrm_state_delete(x1);
1312 xfrm_state_put(x1);
1313 return 0;
1314 }
1315
1316 err = -EINVAL;
1317 spin_lock_bh(&x1->lock);
1318 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1319 if (x->encap && x1->encap)
1320 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001321 if (x->coaddr && x1->coaddr) {
1322 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1323 }
1324 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1325 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1327 x1->km.dying = 0;
1328
David S. Millera47f0ce2006-08-24 03:54:22 -07001329 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (x1->curlft.use_time)
1331 xfrm_state_check_expire(x1);
1332
1333 err = 0;
1334 }
1335 spin_unlock_bh(&x1->lock);
1336
1337 xfrm_state_put(x1);
1338
1339 return err;
1340}
1341EXPORT_SYMBOL(xfrm_state_update);
1342
1343int xfrm_state_check_expire(struct xfrm_state *x)
1344{
1345 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001346 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 if (x->km.state != XFRM_STATE_VALID)
1349 return -EINVAL;
1350
1351 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1352 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001353 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001354 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 return -EINVAL;
1356 }
1357
1358 if (!x->km.dying &&
1359 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001360 x->curlft.packets >= x->lft.soft_packet_limit)) {
1361 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001362 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 return 0;
1365}
1366EXPORT_SYMBOL(xfrm_state_check_expire);
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368struct xfrm_state *
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001369xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 unsigned short family)
1371{
1372 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001375 x = __xfrm_state_lookup(net, daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return x;
1378}
1379EXPORT_SYMBOL(xfrm_state_lookup);
1380
1381struct xfrm_state *
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001382xfrm_state_lookup_byaddr(struct net *net,
1383 xfrm_address_t *daddr, xfrm_address_t *saddr,
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001384 u8 proto, unsigned short family)
1385{
1386 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001387
1388 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001389 x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001390 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001391 return x;
1392}
1393EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1394
1395struct xfrm_state *
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001396xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto,
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001397 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 int create, unsigned short family)
1399{
1400 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001403 x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 return x;
1407}
1408EXPORT_SYMBOL(xfrm_find_acq);
1409
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001410#ifdef CONFIG_XFRM_SUB_POLICY
1411int
1412xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1413 unsigned short family)
1414{
1415 int err = 0;
1416 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1417 if (!afinfo)
1418 return -EAFNOSUPPORT;
1419
1420 spin_lock_bh(&xfrm_state_lock);
1421 if (afinfo->tmpl_sort)
1422 err = afinfo->tmpl_sort(dst, src, n);
1423 spin_unlock_bh(&xfrm_state_lock);
1424 xfrm_state_put_afinfo(afinfo);
1425 return err;
1426}
1427EXPORT_SYMBOL(xfrm_tmpl_sort);
1428
1429int
1430xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1431 unsigned short family)
1432{
1433 int err = 0;
1434 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1435 if (!afinfo)
1436 return -EAFNOSUPPORT;
1437
1438 spin_lock_bh(&xfrm_state_lock);
1439 if (afinfo->state_sort)
1440 err = afinfo->state_sort(dst, src, n);
1441 spin_unlock_bh(&xfrm_state_lock);
1442 xfrm_state_put_afinfo(afinfo);
1443 return err;
1444}
1445EXPORT_SYMBOL(xfrm_state_sort);
1446#endif
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448/* Silly enough, but I'm lazy to build resolution list */
1449
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001450static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001454 for (i = 0; i <= net->xfrm.state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001455 struct hlist_node *entry;
1456 struct xfrm_state *x;
1457
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001458 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
David S. Miller8f126e32006-08-24 02:45:07 -07001459 if (x->km.seq == seq &&
1460 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 xfrm_state_hold(x);
1462 return x;
1463 }
1464 }
1465 }
1466 return NULL;
1467}
1468
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001469struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
1471 struct xfrm_state *x;
1472
1473 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan5447c5e2008-11-25 17:31:51 -08001474 x = __xfrm_find_acq_byseq(net, seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 spin_unlock_bh(&xfrm_state_lock);
1476 return x;
1477}
1478EXPORT_SYMBOL(xfrm_find_acq_byseq);
1479
1480u32 xfrm_get_acqseq(void)
1481{
1482 u32 res;
1483 static u32 acqseq;
1484 static DEFINE_SPINLOCK(acqseq_lock);
1485
1486 spin_lock_bh(&acqseq_lock);
1487 res = (++acqseq ? : ++acqseq);
1488 spin_unlock_bh(&acqseq_lock);
1489 return res;
1490}
1491EXPORT_SYMBOL(xfrm_get_acqseq);
1492
Herbert Xu658b2192007-10-09 13:29:52 -07001493int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001495 struct net *net = xs_net(x);
David S. Millerf034b5d2006-08-24 03:08:07 -07001496 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001498 int err = -ENOENT;
1499 __be32 minspi = htonl(low);
1500 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Herbert Xu658b2192007-10-09 13:29:52 -07001502 spin_lock_bh(&x->lock);
1503 if (x->km.state == XFRM_STATE_DEAD)
1504 goto unlock;
1505
1506 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001508 goto unlock;
1509
1510 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 if (minspi == maxspi) {
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001513 x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 if (x0) {
1515 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001516 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 }
1518 x->id.spi = minspi;
1519 } else {
1520 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001521 for (h=0; h<high-low+1; h++) {
1522 spi = low + net_random()%(high-low+1);
Alexey Dobriyan221df1e2008-11-25 17:30:50 -08001523 x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (x0 == NULL) {
1525 x->id.spi = htonl(spi);
1526 break;
1527 }
1528 xfrm_state_put(x0);
1529 }
1530 }
1531 if (x->id.spi) {
1532 spin_lock_bh(&xfrm_state_lock);
Alexey Dobriyan12604d82008-11-25 17:31:18 -08001533 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
1534 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001536
1537 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 }
Herbert Xu658b2192007-10-09 13:29:52 -07001539
1540unlock:
1541 spin_unlock_bh(&x->lock);
1542
1543 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544}
1545EXPORT_SYMBOL(xfrm_alloc_spi);
1546
Timo Teras4c563f72008-02-28 21:31:08 -08001547int xfrm_state_walk(struct xfrm_state_walk *walk,
1548 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 void *data)
1550{
Herbert Xu12a169e2008-10-01 07:03:24 -07001551 struct xfrm_state *state;
1552 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 int err = 0;
1554
Herbert Xu12a169e2008-10-01 07:03:24 -07001555 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001556 return 0;
1557
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001559 if (list_empty(&walk->all))
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001560 x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
Herbert Xu12a169e2008-10-01 07:03:24 -07001561 else
1562 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08001563 list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001564 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001565 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001566 state = container_of(x, struct xfrm_state, km);
1567 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001568 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001569 err = func(state, walk->seq, data);
1570 if (err) {
1571 list_move_tail(&walk->all, &x->all);
1572 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001574 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001576 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 err = -ENOENT;
1578 goto out;
1579 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001580 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581out:
1582 spin_unlock_bh(&xfrm_state_lock);
1583 return err;
1584}
1585EXPORT_SYMBOL(xfrm_state_walk);
1586
Herbert Xu5c182452008-09-22 19:48:19 -07001587void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1588{
Herbert Xu12a169e2008-10-01 07:03:24 -07001589 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001590 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001591 walk->state = XFRM_STATE_DEAD;
1592 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001593}
1594EXPORT_SYMBOL(xfrm_state_walk_init);
1595
Herbert Xuabb81c42008-09-09 19:58:29 -07001596void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1597{
Herbert Xu12a169e2008-10-01 07:03:24 -07001598 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001599 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001600
Herbert Xu12a169e2008-10-01 07:03:24 -07001601 spin_lock_bh(&xfrm_state_lock);
1602 list_del(&walk->all);
1603 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001604}
1605EXPORT_SYMBOL(xfrm_state_walk_done);
1606
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001607
1608void xfrm_replay_notify(struct xfrm_state *x, int event)
1609{
1610 struct km_event c;
1611 /* we send notify messages in case
1612 * 1. we updated on of the sequence numbers, and the seqno difference
1613 * is at least x->replay_maxdiff, in this case we also update the
1614 * timeout of our timer function
1615 * 2. if x->replay_maxage has elapsed since last update,
1616 * and there were changes
1617 *
1618 * The state structure must be locked!
1619 */
1620
1621 switch (event) {
1622 case XFRM_REPLAY_UPDATE:
1623 if (x->replay_maxdiff &&
1624 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001625 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1626 if (x->xflags & XFRM_TIME_DEFER)
1627 event = XFRM_REPLAY_TIMEOUT;
1628 else
1629 return;
1630 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001631
1632 break;
1633
1634 case XFRM_REPLAY_TIMEOUT:
1635 if ((x->replay.seq == x->preplay.seq) &&
1636 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001637 (x->replay.oseq == x->preplay.oseq)) {
1638 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001639 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001640 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001641
1642 break;
1643 }
1644
1645 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1646 c.event = XFRM_MSG_NEWAE;
1647 c.data.aevent = event;
1648 km_state_notify(x, &c);
1649
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001650 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001651 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001652 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001653}
1654
1655static void xfrm_replay_timer_handler(unsigned long data)
1656{
1657 struct xfrm_state *x = (struct xfrm_state*)data;
1658
1659 spin_lock(&x->lock);
1660
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001661 if (x->km.state == XFRM_STATE_VALID) {
1662 if (xfrm_aevent_is_on())
1663 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1664 else
1665 x->xflags |= XFRM_TIME_DEFER;
1666 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001667
1668 spin_unlock(&x->lock);
1669}
1670
Paul Mooreafeb14b2007-12-21 14:58:11 -08001671int xfrm_replay_check(struct xfrm_state *x,
1672 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673{
1674 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001675 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
1677 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001678 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
1680 if (likely(seq > x->replay.seq))
1681 return 0;
1682
1683 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001684 if (diff >= min_t(unsigned int, x->props.replay_window,
1685 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001687 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 }
1689
1690 if (x->replay.bitmap & (1U << diff)) {
1691 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001692 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 }
1694 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001695
1696err:
1697 xfrm_audit_state_replay(x, skb, net_seq);
1698 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
Al Viro61f46272006-09-27 18:48:33 -07001701void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702{
1703 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001704 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
1706 if (seq > x->replay.seq) {
1707 diff = seq - x->replay.seq;
1708 if (diff < x->props.replay_window)
1709 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1710 else
1711 x->replay.bitmap = 1;
1712 x->replay.seq = seq;
1713 } else {
1714 diff = x->replay.seq - seq;
1715 x->replay.bitmap |= (1U << diff);
1716 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001717
1718 if (xfrm_aevent_is_on())
1719 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
Denis Chengdf018122007-12-07 00:51:11 -08001722static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723static DEFINE_RWLOCK(xfrm_km_lock);
1724
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001725void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726{
1727 struct xfrm_mgr *km;
1728
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001729 read_lock(&xfrm_km_lock);
1730 list_for_each_entry(km, &xfrm_km_list, list)
1731 if (km->notify_policy)
1732 km->notify_policy(xp, dir, c);
1733 read_unlock(&xfrm_km_lock);
1734}
1735
1736void km_state_notify(struct xfrm_state *x, struct km_event *c)
1737{
1738 struct xfrm_mgr *km;
1739 read_lock(&xfrm_km_lock);
1740 list_for_each_entry(km, &xfrm_km_list, list)
1741 if (km->notify)
1742 km->notify(x, c);
1743 read_unlock(&xfrm_km_lock);
1744}
1745
1746EXPORT_SYMBOL(km_policy_notify);
1747EXPORT_SYMBOL(km_state_notify);
1748
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001749void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001750{
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001751 struct net *net = xs_net(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001752 struct km_event c;
1753
Herbert Xubf088672005-06-18 22:44:00 -07001754 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001755 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001756 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001757 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
1759 if (hard)
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001760 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761}
1762
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001763EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001764/*
1765 * We send to all registered managers regardless of failure
1766 * We are happy with one success
1767*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001768int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001770 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 struct xfrm_mgr *km;
1772
1773 read_lock(&xfrm_km_lock);
1774 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001775 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1776 if (!acqret)
1777 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 }
1779 read_unlock(&xfrm_km_lock);
1780 return err;
1781}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001782EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Al Viro5d36b182006-11-08 00:24:06 -08001784int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785{
1786 int err = -EINVAL;
1787 struct xfrm_mgr *km;
1788
1789 read_lock(&xfrm_km_lock);
1790 list_for_each_entry(km, &xfrm_km_list, list) {
1791 if (km->new_mapping)
1792 err = km->new_mapping(x, ipaddr, sport);
1793 if (!err)
1794 break;
1795 }
1796 read_unlock(&xfrm_km_lock);
1797 return err;
1798}
1799EXPORT_SYMBOL(km_new_mapping);
1800
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001801void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802{
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001803 struct net *net = xp_net(pol);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001804 struct km_event c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Herbert Xubf088672005-06-18 22:44:00 -07001806 c.data.hard = hard;
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001807 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001808 c.event = XFRM_MSG_POLEXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001809 km_policy_notify(pol, dir, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
1811 if (hard)
Alexey Dobriyan98806f72008-11-25 17:29:47 -08001812 wake_up(&net->xfrm.km_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813}
David S. Millera70fcb02006-03-20 19:18:52 -08001814EXPORT_SYMBOL(km_policy_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001816#ifdef CONFIG_XFRM_MIGRATE
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001817int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001818 struct xfrm_migrate *m, int num_migrate,
1819 struct xfrm_kmaddress *k)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001820{
1821 int err = -EINVAL;
1822 int ret;
1823 struct xfrm_mgr *km;
1824
1825 read_lock(&xfrm_km_lock);
1826 list_for_each_entry(km, &xfrm_km_list, list) {
1827 if (km->migrate) {
Arnaud Ebalard13c1d182008-10-05 13:33:42 -07001828 ret = km->migrate(sel, dir, type, m, num_migrate, k);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001829 if (!ret)
1830 err = ret;
1831 }
1832 }
1833 read_unlock(&xfrm_km_lock);
1834 return err;
1835}
1836EXPORT_SYMBOL(km_migrate);
Eric Dumazet2d60abc2008-01-03 20:43:21 -08001837#endif
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001838
Masahide NAKAMURA97a64b42006-08-23 20:44:06 -07001839int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1840{
1841 int err = -EINVAL;
1842 int ret;
1843 struct xfrm_mgr *km;
1844
1845 read_lock(&xfrm_km_lock);
1846 list_for_each_entry(km, &xfrm_km_list, list) {
1847 if (km->report) {
1848 ret = km->report(proto, sel, addr);
1849 if (!ret)
1850 err = ret;
1851 }
1852 }
1853 read_unlock(&xfrm_km_lock);
1854 return err;
1855}
1856EXPORT_SYMBOL(km_report);
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1859{
1860 int err;
1861 u8 *data;
1862 struct xfrm_mgr *km;
1863 struct xfrm_policy *pol = NULL;
1864
1865 if (optlen <= 0 || optlen > PAGE_SIZE)
1866 return -EMSGSIZE;
1867
1868 data = kmalloc(optlen, GFP_KERNEL);
1869 if (!data)
1870 return -ENOMEM;
1871
1872 err = -EFAULT;
1873 if (copy_from_user(data, optval, optlen))
1874 goto out;
1875
1876 err = -EINVAL;
1877 read_lock(&xfrm_km_lock);
1878 list_for_each_entry(km, &xfrm_km_list, list) {
Venkat Yekkiralacb969f02006-07-24 23:32:20 -07001879 pol = km->compile_policy(sk, optname, data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 optlen, &err);
1881 if (err >= 0)
1882 break;
1883 }
1884 read_unlock(&xfrm_km_lock);
1885
1886 if (err >= 0) {
1887 xfrm_sk_policy_insert(sk, err, pol);
1888 xfrm_pol_put(pol);
1889 err = 0;
1890 }
1891
1892out:
1893 kfree(data);
1894 return err;
1895}
1896EXPORT_SYMBOL(xfrm_user_policy);
1897
1898int xfrm_register_km(struct xfrm_mgr *km)
1899{
1900 write_lock_bh(&xfrm_km_lock);
1901 list_add_tail(&km->list, &xfrm_km_list);
1902 write_unlock_bh(&xfrm_km_lock);
1903 return 0;
1904}
1905EXPORT_SYMBOL(xfrm_register_km);
1906
1907int xfrm_unregister_km(struct xfrm_mgr *km)
1908{
1909 write_lock_bh(&xfrm_km_lock);
1910 list_del(&km->list);
1911 write_unlock_bh(&xfrm_km_lock);
1912 return 0;
1913}
1914EXPORT_SYMBOL(xfrm_unregister_km);
1915
1916int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1917{
1918 int err = 0;
1919 if (unlikely(afinfo == NULL))
1920 return -EINVAL;
1921 if (unlikely(afinfo->family >= NPROTO))
1922 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001923 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1925 err = -ENOBUFS;
David S. Milleredcd5822006-08-24 00:42:45 -07001926 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 xfrm_state_afinfo[afinfo->family] = afinfo;
Ingo Molnarf3111502006-04-28 15:30:03 -07001928 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 return err;
1930}
1931EXPORT_SYMBOL(xfrm_state_register_afinfo);
1932
1933int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1934{
1935 int err = 0;
1936 if (unlikely(afinfo == NULL))
1937 return -EINVAL;
1938 if (unlikely(afinfo->family >= NPROTO))
1939 return -EAFNOSUPPORT;
Ingo Molnarf3111502006-04-28 15:30:03 -07001940 write_lock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1942 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1943 err = -EINVAL;
David S. Milleredcd5822006-08-24 00:42:45 -07001944 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 xfrm_state_afinfo[afinfo->family] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 }
Ingo Molnarf3111502006-04-28 15:30:03 -07001947 write_unlock_bh(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 return err;
1949}
1950EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1951
Herbert Xu17c2a422007-10-17 21:33:12 -07001952static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953{
1954 struct xfrm_state_afinfo *afinfo;
1955 if (unlikely(family >= NPROTO))
1956 return NULL;
1957 read_lock(&xfrm_state_afinfo_lock);
1958 afinfo = xfrm_state_afinfo[family];
Herbert Xu546be242006-05-27 23:03:58 -07001959 if (unlikely(!afinfo))
1960 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return afinfo;
1962}
1963
Herbert Xu17c2a422007-10-17 21:33:12 -07001964static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -08001965 __releases(xfrm_state_afinfo_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
Herbert Xu546be242006-05-27 23:03:58 -07001967 read_unlock(&xfrm_state_afinfo_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968}
1969
1970/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
1971void xfrm_state_delete_tunnel(struct xfrm_state *x)
1972{
1973 if (x->tunnel) {
1974 struct xfrm_state *t = x->tunnel;
1975
1976 if (atomic_read(&t->tunnel_users) == 2)
1977 xfrm_state_delete(t);
1978 atomic_dec(&t->tunnel_users);
1979 xfrm_state_put(t);
1980 x->tunnel = NULL;
1981 }
1982}
1983EXPORT_SYMBOL(xfrm_state_delete_tunnel);
1984
1985int xfrm_state_mtu(struct xfrm_state *x, int mtu)
1986{
Patrick McHardyc5c25232007-04-09 11:47:18 -07001987 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Patrick McHardyc5c25232007-04-09 11:47:18 -07001989 spin_lock_bh(&x->lock);
1990 if (x->km.state == XFRM_STATE_VALID &&
1991 x->type && x->type->get_mtu)
1992 res = x->type->get_mtu(x, mtu);
1993 else
Patrick McHardy28121612007-06-18 22:30:15 -07001994 res = mtu - x->props.header_len;
Patrick McHardyc5c25232007-04-09 11:47:18 -07001995 spin_unlock_bh(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 return res;
1997}
1998
Herbert Xu72cb6962005-06-20 13:18:08 -07001999int xfrm_init_state(struct xfrm_state *x)
2000{
Herbert Xud094cd82005-06-20 13:19:41 -07002001 struct xfrm_state_afinfo *afinfo;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002002 struct xfrm_mode *inner_mode;
Herbert Xud094cd82005-06-20 13:19:41 -07002003 int family = x->props.family;
Herbert Xu72cb6962005-06-20 13:18:08 -07002004 int err;
2005
Herbert Xud094cd82005-06-20 13:19:41 -07002006 err = -EAFNOSUPPORT;
2007 afinfo = xfrm_state_get_afinfo(family);
2008 if (!afinfo)
2009 goto error;
2010
2011 err = 0;
2012 if (afinfo->init_flags)
2013 err = afinfo->init_flags(x);
2014
2015 xfrm_state_put_afinfo(afinfo);
2016
2017 if (err)
2018 goto error;
2019
2020 err = -EPROTONOSUPPORT;
Herbert Xu13996372007-10-17 21:35:51 -07002021
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -07002022 if (x->sel.family != AF_UNSPEC) {
2023 inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2024 if (inner_mode == NULL)
2025 goto error;
2026
2027 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2028 family != x->sel.family) {
2029 xfrm_put_mode(inner_mode);
2030 goto error;
2031 }
2032
2033 x->inner_mode = inner_mode;
2034 } else {
2035 struct xfrm_mode *inner_mode_iaf;
2036
2037 inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
2038 if (inner_mode == NULL)
2039 goto error;
2040
2041 if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
2042 xfrm_put_mode(inner_mode);
2043 goto error;
2044 }
2045
2046 inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
2047 if (inner_mode_iaf == NULL)
2048 goto error;
2049
2050 if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
2051 xfrm_put_mode(inner_mode_iaf);
2052 goto error;
2053 }
2054
2055 if (x->props.family == AF_INET) {
2056 x->inner_mode = inner_mode;
2057 x->inner_mode_iaf = inner_mode_iaf;
2058 } else {
2059 x->inner_mode = inner_mode_iaf;
2060 x->inner_mode_iaf = inner_mode;
2061 }
2062 }
Herbert Xu13996372007-10-17 21:35:51 -07002063
Herbert Xud094cd82005-06-20 13:19:41 -07002064 x->type = xfrm_get_type(x->id.proto, family);
Herbert Xu72cb6962005-06-20 13:18:08 -07002065 if (x->type == NULL)
2066 goto error;
2067
2068 err = x->type->init_state(x);
2069 if (err)
2070 goto error;
2071
Herbert Xu13996372007-10-17 21:35:51 -07002072 x->outer_mode = xfrm_get_mode(x->props.mode, family);
2073 if (x->outer_mode == NULL)
Herbert Xub59f45d2006-05-27 23:05:54 -07002074 goto error;
2075
Herbert Xu72cb6962005-06-20 13:18:08 -07002076 x->km.state = XFRM_STATE_VALID;
2077
2078error:
2079 return err;
2080}
2081
2082EXPORT_SYMBOL(xfrm_init_state);
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09002083
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002084int __net_init xfrm_state_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085{
David S. Millerf034b5d2006-08-24 03:08:07 -07002086 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002088 INIT_LIST_HEAD(&net->xfrm.state_all);
2089
David S. Millerf034b5d2006-08-24 03:08:07 -07002090 sz = sizeof(struct hlist_head) * 8;
2091
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002092 net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2093 if (!net->xfrm.state_bydst)
2094 goto out_bydst;
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002095 net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2096 if (!net->xfrm.state_bysrc)
2097 goto out_bysrc;
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002098 net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2099 if (!net->xfrm.state_byspi)
2100 goto out_byspi;
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002101 net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
David S. Millerf034b5d2006-08-24 03:08:07 -07002102
Alexey Dobriyan0bf7c5b2008-11-25 17:18:39 -08002103 net->xfrm.state_num = 0;
Alexey Dobriyan63082732008-11-25 17:19:07 -08002104 INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
Alexey Dobriyanb8a0ae22008-11-25 17:20:11 -08002105 INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
Alexey Dobriyanc7837142008-11-25 17:20:36 -08002106 INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
Alexey Dobriyan50a30652008-11-25 17:21:01 -08002107 init_waitqueue_head(&net->xfrm.km_waitq);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002108 return 0;
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002109
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002110out_byspi:
2111 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002112out_bysrc:
2113 xfrm_hash_free(net->xfrm.state_bydst, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002114out_bydst:
2115 return -ENOMEM;
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002116}
2117
2118void xfrm_state_fini(struct net *net)
2119{
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002120 unsigned int sz;
2121
Alexey Dobriyan9d4139c2008-11-25 17:16:11 -08002122 WARN_ON(!list_empty(&net->xfrm.state_all));
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002123
Alexey Dobriyan529983e2008-11-25 17:18:12 -08002124 sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
Alexey Dobriyanb754a4f2008-11-25 17:17:47 -08002125 WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2126 xfrm_hash_free(net->xfrm.state_byspi, sz);
Alexey Dobriyand320bbb2008-11-25 17:17:24 -08002127 WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2128 xfrm_hash_free(net->xfrm.state_bysrc, sz);
Alexey Dobriyan73d189d2008-11-25 17:16:58 -08002129 WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2130 xfrm_hash_free(net->xfrm.state_bydst, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131}
2132
Joy Lattenab5f5e82007-09-17 11:51:22 -07002133#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002134static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2135 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002136{
Paul Moore68277ac2007-12-20 20:49:33 -08002137 struct xfrm_sec_ctx *ctx = x->security;
2138 u32 spi = ntohl(x->id.spi);
2139
2140 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002141 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002142 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002143
2144 switch(x->props.family) {
2145 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002146 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2147 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002148 break;
2149 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002150 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002151 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002152 break;
2153 }
Paul Moore68277ac2007-12-20 20:49:33 -08002154
2155 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002156}
2157
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002158static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2159 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002160{
2161 struct iphdr *iph4;
2162 struct ipv6hdr *iph6;
2163
2164 switch (family) {
2165 case AF_INET:
2166 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002167 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2168 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002169 break;
2170 case AF_INET6:
2171 iph6 = ipv6_hdr(skb);
2172 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002173 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002174 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002175 iph6->flow_lbl[0] & 0x0f,
2176 iph6->flow_lbl[1],
2177 iph6->flow_lbl[2]);
2178 break;
2179 }
2180}
2181
Paul Moore68277ac2007-12-20 20:49:33 -08002182void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002183 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002184{
2185 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002186
Paul Mooreafeb14b2007-12-21 14:58:11 -08002187 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002188 if (audit_buf == NULL)
2189 return;
Eric Paris25323862008-04-18 10:09:25 -04002190 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002191 xfrm_audit_helper_sainfo(x, audit_buf);
2192 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002193 audit_log_end(audit_buf);
2194}
2195EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2196
Paul Moore68277ac2007-12-20 20:49:33 -08002197void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002198 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002199{
2200 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002201
Paul Mooreafeb14b2007-12-21 14:58:11 -08002202 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002203 if (audit_buf == NULL)
2204 return;
Eric Paris25323862008-04-18 10:09:25 -04002205 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002206 xfrm_audit_helper_sainfo(x, audit_buf);
2207 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002208 audit_log_end(audit_buf);
2209}
2210EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002211
2212void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2213 struct sk_buff *skb)
2214{
2215 struct audit_buffer *audit_buf;
2216 u32 spi;
2217
2218 audit_buf = xfrm_audit_start("SA-replay-overflow");
2219 if (audit_buf == NULL)
2220 return;
2221 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2222 /* don't record the sequence number because it's inherent in this kind
2223 * of audit message */
2224 spi = ntohl(x->id.spi);
2225 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2226 audit_log_end(audit_buf);
2227}
2228EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2229
2230static void xfrm_audit_state_replay(struct xfrm_state *x,
2231 struct sk_buff *skb, __be32 net_seq)
2232{
2233 struct audit_buffer *audit_buf;
2234 u32 spi;
2235
2236 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2237 if (audit_buf == NULL)
2238 return;
2239 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2240 spi = ntohl(x->id.spi);
2241 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2242 spi, spi, ntohl(net_seq));
2243 audit_log_end(audit_buf);
2244}
2245
2246void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2247{
2248 struct audit_buffer *audit_buf;
2249
2250 audit_buf = xfrm_audit_start("SA-notfound");
2251 if (audit_buf == NULL)
2252 return;
2253 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2254 audit_log_end(audit_buf);
2255}
2256EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2257
2258void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2259 __be32 net_spi, __be32 net_seq)
2260{
2261 struct audit_buffer *audit_buf;
2262 u32 spi;
2263
2264 audit_buf = xfrm_audit_start("SA-notfound");
2265 if (audit_buf == NULL)
2266 return;
2267 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2268 spi = ntohl(net_spi);
2269 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2270 spi, spi, ntohl(net_seq));
2271 audit_log_end(audit_buf);
2272}
2273EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2274
2275void xfrm_audit_state_icvfail(struct xfrm_state *x,
2276 struct sk_buff *skb, u8 proto)
2277{
2278 struct audit_buffer *audit_buf;
2279 __be32 net_spi;
2280 __be32 net_seq;
2281
2282 audit_buf = xfrm_audit_start("SA-icv-failure");
2283 if (audit_buf == NULL)
2284 return;
2285 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2286 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2287 u32 spi = ntohl(net_spi);
2288 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2289 spi, spi, ntohl(net_seq));
2290 }
2291 audit_log_end(audit_buf);
2292}
2293EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002294#endif /* CONFIG_AUDITSYSCALL */