blob: 81bde76d049c30a7a7dde62c4cbd0a8b247241b1 [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
47/* Hash table to find appropriate SA towards given target (endpoint
48 * of tunnel or destination of transport mode) allowed by selector.
49 *
50 * Main use is finding SA after policy selected tunnel or transport mode.
51 * Also, it can be used by ah/esp icmp error handler to find offending SA.
52 */
Timo Teras4c563f72008-02-28 21:31:08 -080053static LIST_HEAD(xfrm_state_all);
David S. Millerf034b5d2006-08-24 03:08:07 -070054static struct hlist_head *xfrm_state_bydst __read_mostly;
55static struct hlist_head *xfrm_state_bysrc __read_mostly;
56static struct hlist_head *xfrm_state_byspi __read_mostly;
57static unsigned int xfrm_state_hmask __read_mostly;
58static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
59static unsigned int xfrm_state_num;
David S. Miller9d4a7062006-08-24 03:18:09 -070060static unsigned int xfrm_state_genid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Herbert Xu17c2a422007-10-17 21:33:12 -070062static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
63static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
64
Paul Mooreafeb14b2007-12-21 14:58:11 -080065#ifdef CONFIG_AUDITSYSCALL
66static void xfrm_audit_state_replay(struct xfrm_state *x,
67 struct sk_buff *skb, __be32 net_seq);
68#else
69#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
70#endif /* CONFIG_AUDITSYSCALL */
71
David S. Millerc1969f22006-08-24 04:00:03 -070072static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
73 xfrm_address_t *saddr,
74 u32 reqid,
David S. Millera624c102006-08-24 03:24:33 -070075 unsigned short family)
76{
David S. Millerc1969f22006-08-24 04:00:03 -070077 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
David S. Millera624c102006-08-24 03:24:33 -070078}
79
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070080static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
81 xfrm_address_t *saddr,
David S. Miller44e36b42006-08-24 04:50:50 -070082 unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070083{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -070084 return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070085}
86
David S. Miller2575b652006-08-24 03:26:44 -070087static inline unsigned int
Al Viro8122adf2006-09-27 18:49:35 -070088xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Millerf034b5d2006-08-24 03:08:07 -070089{
David S. Millerc1969f22006-08-24 04:00:03 -070090 return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
David S. Millerf034b5d2006-08-24 03:08:07 -070091}
92
David S. Millerf034b5d2006-08-24 03:08:07 -070093static void xfrm_hash_transfer(struct hlist_head *list,
94 struct hlist_head *ndsttable,
95 struct hlist_head *nsrctable,
96 struct hlist_head *nspitable,
97 unsigned int nhashmask)
98{
99 struct hlist_node *entry, *tmp;
100 struct xfrm_state *x;
101
102 hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {
103 unsigned int h;
104
David S. Millerc1969f22006-08-24 04:00:03 -0700105 h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
106 x->props.reqid, x->props.family,
107 nhashmask);
David S. Millerf034b5d2006-08-24 03:08:07 -0700108 hlist_add_head(&x->bydst, ndsttable+h);
109
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700110 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
111 x->props.family,
David S. Millerf034b5d2006-08-24 03:08:07 -0700112 nhashmask);
113 hlist_add_head(&x->bysrc, nsrctable+h);
114
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700115 if (x->id.spi) {
116 h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
117 x->id.proto, x->props.family,
118 nhashmask);
119 hlist_add_head(&x->byspi, nspitable+h);
120 }
David S. Millerf034b5d2006-08-24 03:08:07 -0700121 }
122}
123
124static unsigned long xfrm_hash_new_size(void)
125{
126 return ((xfrm_state_hmask + 1) << 1) *
127 sizeof(struct hlist_head);
128}
129
130static DEFINE_MUTEX(hash_resize_mutex);
131
David Howellsc4028952006-11-22 14:57:56 +0000132static void xfrm_hash_resize(struct work_struct *__unused)
David S. Millerf034b5d2006-08-24 03:08:07 -0700133{
134 struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
135 unsigned long nsize, osize;
136 unsigned int nhashmask, ohashmask;
137 int i;
138
139 mutex_lock(&hash_resize_mutex);
140
141 nsize = xfrm_hash_new_size();
David S. Miller44e36b42006-08-24 04:50:50 -0700142 ndst = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700143 if (!ndst)
144 goto out_unlock;
David S. Miller44e36b42006-08-24 04:50:50 -0700145 nsrc = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700146 if (!nsrc) {
David S. Miller44e36b42006-08-24 04:50:50 -0700147 xfrm_hash_free(ndst, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700148 goto out_unlock;
149 }
David S. Miller44e36b42006-08-24 04:50:50 -0700150 nspi = xfrm_hash_alloc(nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700151 if (!nspi) {
David S. Miller44e36b42006-08-24 04:50:50 -0700152 xfrm_hash_free(ndst, nsize);
153 xfrm_hash_free(nsrc, nsize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700154 goto out_unlock;
155 }
156
157 spin_lock_bh(&xfrm_state_lock);
158
159 nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
160 for (i = xfrm_state_hmask; i >= 0; i--)
161 xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,
162 nhashmask);
163
164 odst = xfrm_state_bydst;
165 osrc = xfrm_state_bysrc;
166 ospi = xfrm_state_byspi;
167 ohashmask = xfrm_state_hmask;
168
169 xfrm_state_bydst = ndst;
170 xfrm_state_bysrc = nsrc;
171 xfrm_state_byspi = nspi;
172 xfrm_state_hmask = nhashmask;
173
174 spin_unlock_bh(&xfrm_state_lock);
175
176 osize = (ohashmask + 1) * sizeof(struct hlist_head);
David S. Miller44e36b42006-08-24 04:50:50 -0700177 xfrm_hash_free(odst, osize);
178 xfrm_hash_free(osrc, osize);
179 xfrm_hash_free(ospi, osize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700180
181out_unlock:
182 mutex_unlock(&hash_resize_mutex);
183}
184
David Howellsc4028952006-11-22 14:57:56 +0000185static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
David S. Millerf034b5d2006-08-24 03:08:07 -0700186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187DECLARE_WAIT_QUEUE_HEAD(km_waitq);
188EXPORT_SYMBOL(km_waitq);
189
190static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
191static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
192
193static struct work_struct xfrm_state_gc_work;
Herbert Xu12a169e2008-10-01 07:03:24 -0700194static HLIST_HEAD(xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195static DEFINE_SPINLOCK(xfrm_state_gc_lock);
196
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800197int __xfrm_state_delete(struct xfrm_state *x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -0800199int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800200void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700202static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
203{
204 struct xfrm_state_afinfo *afinfo;
205 if (unlikely(family >= NPROTO))
206 return NULL;
207 write_lock_bh(&xfrm_state_afinfo_lock);
208 afinfo = xfrm_state_afinfo[family];
209 if (unlikely(!afinfo))
210 write_unlock_bh(&xfrm_state_afinfo_lock);
211 return afinfo;
212}
213
214static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
Eric Dumazet9a429c42008-01-01 21:58:02 -0800215 __releases(xfrm_state_afinfo_lock)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700216{
217 write_unlock_bh(&xfrm_state_afinfo_lock);
218}
219
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800220int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700221{
222 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800223 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700224 int err = 0;
225
226 if (unlikely(afinfo == NULL))
227 return -EAFNOSUPPORT;
228 typemap = afinfo->type_map;
229
230 if (likely(typemap[type->proto] == NULL))
231 typemap[type->proto] = type;
232 else
233 err = -EEXIST;
234 xfrm_state_unlock_afinfo(afinfo);
235 return err;
236}
237EXPORT_SYMBOL(xfrm_register_type);
238
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800239int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700240{
241 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800242 const struct xfrm_type **typemap;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700243 int err = 0;
244
245 if (unlikely(afinfo == NULL))
246 return -EAFNOSUPPORT;
247 typemap = afinfo->type_map;
248
249 if (unlikely(typemap[type->proto] != type))
250 err = -ENOENT;
251 else
252 typemap[type->proto] = NULL;
253 xfrm_state_unlock_afinfo(afinfo);
254 return err;
255}
256EXPORT_SYMBOL(xfrm_unregister_type);
257
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800258static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700259{
260 struct xfrm_state_afinfo *afinfo;
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800261 const struct xfrm_type **typemap;
262 const struct xfrm_type *type;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700263 int modload_attempted = 0;
264
265retry:
266 afinfo = xfrm_state_get_afinfo(family);
267 if (unlikely(afinfo == NULL))
268 return NULL;
269 typemap = afinfo->type_map;
270
271 type = typemap[proto];
272 if (unlikely(type && !try_module_get(type->owner)))
273 type = NULL;
274 if (!type && !modload_attempted) {
275 xfrm_state_put_afinfo(afinfo);
276 request_module("xfrm-type-%d-%d", family, proto);
277 modload_attempted = 1;
278 goto retry;
279 }
280
281 xfrm_state_put_afinfo(afinfo);
282 return type;
283}
284
Eric Dumazet533cb5b2008-01-30 19:11:50 -0800285static void xfrm_put_type(const struct xfrm_type *type)
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700286{
287 module_put(type->owner);
288}
289
290int xfrm_register_mode(struct xfrm_mode *mode, int family)
291{
292 struct xfrm_state_afinfo *afinfo;
293 struct xfrm_mode **modemap;
294 int err;
295
296 if (unlikely(mode->encap >= XFRM_MODE_MAX))
297 return -EINVAL;
298
299 afinfo = xfrm_state_lock_afinfo(family);
300 if (unlikely(afinfo == NULL))
301 return -EAFNOSUPPORT;
302
303 err = -EEXIST;
304 modemap = afinfo->mode_map;
Herbert Xu17c2a422007-10-17 21:33:12 -0700305 if (modemap[mode->encap])
306 goto out;
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700307
Herbert Xu17c2a422007-10-17 21:33:12 -0700308 err = -ENOENT;
309 if (!try_module_get(afinfo->owner))
310 goto out;
311
312 mode->afinfo = afinfo;
313 modemap[mode->encap] = mode;
314 err = 0;
315
316out:
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700317 xfrm_state_unlock_afinfo(afinfo);
318 return err;
319}
320EXPORT_SYMBOL(xfrm_register_mode);
321
322int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
323{
324 struct xfrm_state_afinfo *afinfo;
325 struct xfrm_mode **modemap;
326 int err;
327
328 if (unlikely(mode->encap >= XFRM_MODE_MAX))
329 return -EINVAL;
330
331 afinfo = xfrm_state_lock_afinfo(family);
332 if (unlikely(afinfo == NULL))
333 return -EAFNOSUPPORT;
334
335 err = -ENOENT;
336 modemap = afinfo->mode_map;
337 if (likely(modemap[mode->encap] == mode)) {
338 modemap[mode->encap] = NULL;
Herbert Xu17c2a422007-10-17 21:33:12 -0700339 module_put(mode->afinfo->owner);
Herbert Xuaa5d62c2007-10-17 21:31:12 -0700340 err = 0;
341 }
342
343 xfrm_state_unlock_afinfo(afinfo);
344 return err;
345}
346EXPORT_SYMBOL(xfrm_unregister_mode);
347
348static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
349{
350 struct xfrm_state_afinfo *afinfo;
351 struct xfrm_mode *mode;
352 int modload_attempted = 0;
353
354 if (unlikely(encap >= XFRM_MODE_MAX))
355 return NULL;
356
357retry:
358 afinfo = xfrm_state_get_afinfo(family);
359 if (unlikely(afinfo == NULL))
360 return NULL;
361
362 mode = afinfo->mode_map[encap];
363 if (unlikely(mode && !try_module_get(mode->owner)))
364 mode = NULL;
365 if (!mode && !modload_attempted) {
366 xfrm_state_put_afinfo(afinfo);
367 request_module("xfrm-mode-%d-%d", family, encap);
368 modload_attempted = 1;
369 goto retry;
370 }
371
372 xfrm_state_put_afinfo(afinfo);
373 return mode;
374}
375
376static void xfrm_put_mode(struct xfrm_mode *mode)
377{
378 module_put(mode->owner);
379}
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381static void xfrm_state_gc_destroy(struct xfrm_state *x)
382{
David S. Millera47f0ce2006-08-24 03:54:22 -0700383 del_timer_sync(&x->timer);
384 del_timer_sync(&x->rtimer);
Jesper Juhla51482b2005-11-08 09:41:34 -0800385 kfree(x->aalg);
386 kfree(x->ealg);
387 kfree(x->calg);
388 kfree(x->encap);
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -0700389 kfree(x->coaddr);
Herbert Xu13996372007-10-17 21:35:51 -0700390 if (x->inner_mode)
391 xfrm_put_mode(x->inner_mode);
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700392 if (x->inner_mode_iaf)
393 xfrm_put_mode(x->inner_mode_iaf);
Herbert Xu13996372007-10-17 21:35:51 -0700394 if (x->outer_mode)
395 xfrm_put_mode(x->outer_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if (x->type) {
397 x->type->destructor(x);
398 xfrm_put_type(x->type);
399 }
Trent Jaegerdf718372005-12-13 23:12:27 -0800400 security_xfrm_state_free(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 kfree(x);
402}
403
David Howellsc4028952006-11-22 14:57:56 +0000404static void xfrm_state_gc_task(struct work_struct *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405{
Herbert Xu12a169e2008-10-01 07:03:24 -0700406 struct xfrm_state *x;
407 struct hlist_node *entry, *tmp;
408 struct hlist_head gc_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700411 hlist_move_list(&xfrm_state_gc_list, &gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 spin_unlock_bh(&xfrm_state_gc_lock);
413
Herbert Xu12a169e2008-10-01 07:03:24 -0700414 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 xfrm_state_gc_destroy(x);
David S. Miller8f126e32006-08-24 02:45:07 -0700416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 wake_up(&km_waitq);
418}
419
420static inline unsigned long make_jiffies(long secs)
421{
422 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
423 return MAX_SCHEDULE_TIMEOUT-1;
424 else
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900425 return secs*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
428static void xfrm_timer_handler(unsigned long data)
429{
430 struct xfrm_state *x = (struct xfrm_state*)data;
James Morris9d729f72007-03-04 16:12:44 -0800431 unsigned long now = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 long next = LONG_MAX;
433 int warn = 0;
Joy Latten161a09e2006-11-27 13:11:54 -0600434 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 spin_lock(&x->lock);
437 if (x->km.state == XFRM_STATE_DEAD)
438 goto out;
439 if (x->km.state == XFRM_STATE_EXPIRED)
440 goto expired;
441 if (x->lft.hard_add_expires_seconds) {
442 long tmo = x->lft.hard_add_expires_seconds +
443 x->curlft.add_time - now;
444 if (tmo <= 0)
445 goto expired;
446 if (tmo < next)
447 next = tmo;
448 }
449 if (x->lft.hard_use_expires_seconds) {
450 long tmo = x->lft.hard_use_expires_seconds +
451 (x->curlft.use_time ? : now) - now;
452 if (tmo <= 0)
453 goto expired;
454 if (tmo < next)
455 next = tmo;
456 }
457 if (x->km.dying)
458 goto resched;
459 if (x->lft.soft_add_expires_seconds) {
460 long tmo = x->lft.soft_add_expires_seconds +
461 x->curlft.add_time - now;
462 if (tmo <= 0)
463 warn = 1;
464 else if (tmo < next)
465 next = tmo;
466 }
467 if (x->lft.soft_use_expires_seconds) {
468 long tmo = x->lft.soft_use_expires_seconds +
469 (x->curlft.use_time ? : now) - now;
470 if (tmo <= 0)
471 warn = 1;
472 else if (tmo < next)
473 next = tmo;
474 }
475
Herbert Xu4666faa2005-06-18 22:43:22 -0700476 x->km.dying = warn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (warn)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800478 km_state_expired(x, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479resched:
David S. Millera47f0ce2006-08-24 03:54:22 -0700480 if (next != LONG_MAX)
481 mod_timer(&x->timer, jiffies + make_jiffies(next));
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 goto out;
484
485expired:
486 if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
487 x->km.state = XFRM_STATE_EXPIRED;
488 wake_up(&km_waitq);
489 next = 2;
490 goto resched;
491 }
Joy Latten161a09e2006-11-27 13:11:54 -0600492
493 err = __xfrm_state_delete(x);
494 if (!err && x->id.spi)
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800495 km_state_expired(x, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Joy Lattenab5f5e82007-09-17 11:51:22 -0700497 xfrm_audit_state_delete(x, err ? 0 : 1,
Eric Paris25323862008-04-18 10:09:25 -0400498 audit_get_loginuid(current),
499 audit_get_sessionid(current), 0);
Joy Latten161a09e2006-11-27 13:11:54 -0600500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501out:
502 spin_unlock(&x->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503}
504
David S. Miller0ac84752006-03-20 19:18:23 -0800505static void xfrm_replay_timer_handler(unsigned long data);
506
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800507struct xfrm_state *xfrm_state_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 struct xfrm_state *x;
510
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700511 x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 if (x) {
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800514 write_pnet(&x->xs_net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 atomic_set(&x->refcnt, 1);
516 atomic_set(&x->tunnel_users, 0);
Herbert Xu12a169e2008-10-01 07:03:24 -0700517 INIT_LIST_HEAD(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700518 INIT_HLIST_NODE(&x->bydst);
519 INIT_HLIST_NODE(&x->bysrc);
520 INIT_HLIST_NODE(&x->byspi);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800521 setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
522 setup_timer(&x->rtimer, xfrm_replay_timer_handler,
523 (unsigned long)x);
James Morris9d729f72007-03-04 16:12:44 -0800524 x->curlft.add_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 x->lft.soft_byte_limit = XFRM_INF;
526 x->lft.soft_packet_limit = XFRM_INF;
527 x->lft.hard_byte_limit = XFRM_INF;
528 x->lft.hard_packet_limit = XFRM_INF;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800529 x->replay_maxage = 0;
530 x->replay_maxdiff = 0;
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700531 x->inner_mode = NULL;
532 x->inner_mode_iaf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 spin_lock_init(&x->lock);
534 }
535 return x;
536}
537EXPORT_SYMBOL(xfrm_state_alloc);
538
539void __xfrm_state_destroy(struct xfrm_state *x)
540{
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700541 WARN_ON(x->km.state != XFRM_STATE_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 spin_lock_bh(&xfrm_state_gc_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700544 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 spin_unlock_bh(&xfrm_state_gc_lock);
546 schedule_work(&xfrm_state_gc_work);
547}
548EXPORT_SYMBOL(__xfrm_state_destroy);
549
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800550int __xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700552 int err = -ESRCH;
553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 if (x->km.state != XFRM_STATE_DEAD) {
555 x->km.state = XFRM_STATE_DEAD;
556 spin_lock(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -0700557 list_del(&x->km.all);
David S. Miller8f126e32006-08-24 02:45:07 -0700558 hlist_del(&x->bydst);
David S. Miller8f126e32006-08-24 02:45:07 -0700559 hlist_del(&x->bysrc);
David S. Millera47f0ce2006-08-24 03:54:22 -0700560 if (x->id.spi)
David S. Miller8f126e32006-08-24 02:45:07 -0700561 hlist_del(&x->byspi);
David S. Millerf034b5d2006-08-24 03:08:07 -0700562 xfrm_state_num--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 spin_unlock(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 /* All xfrm_state objects are created by xfrm_state_alloc.
566 * The xfrm_state_alloc call gives a reference, and that
567 * is what we are dropping here.
568 */
Patrick McHardy5dba4792007-11-27 11:10:07 +0800569 xfrm_state_put(x);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700570 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700572
573 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -0800575EXPORT_SYMBOL(__xfrm_state_delete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700577int xfrm_state_delete(struct xfrm_state *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700579 int err;
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 spin_lock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700582 err = __xfrm_state_delete(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 spin_unlock_bh(&x->lock);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -0700584
585 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587EXPORT_SYMBOL(xfrm_state_delete);
588
Joy Latten4aa2e622007-06-04 19:05:57 -0400589#ifdef CONFIG_SECURITY_NETWORK_XFRM
590static inline int
591xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
Joy Latten4aa2e622007-06-04 19:05:57 -0400593 int i, err = 0;
594
595 for (i = 0; i <= xfrm_state_hmask; i++) {
596 struct hlist_node *entry;
597 struct xfrm_state *x;
598
599 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
600 if (xfrm_id_proto_match(x->id.proto, proto) &&
601 (err = security_xfrm_state_delete(x)) != 0) {
Joy Lattenab5f5e82007-09-17 11:51:22 -0700602 xfrm_audit_state_delete(x, 0,
603 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400604 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700605 audit_info->secid);
Joy Latten4aa2e622007-06-04 19:05:57 -0400606 return err;
607 }
608 }
609 }
610
611 return err;
612}
613#else
614static inline int
615xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
616{
617 return 0;
618}
619#endif
620
621int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
622{
623 int i, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 spin_lock_bh(&xfrm_state_lock);
Joy Latten4aa2e622007-06-04 19:05:57 -0400626 err = xfrm_state_flush_secctx_check(proto, audit_info);
627 if (err)
628 goto out;
629
Masahide NAKAMURAa9917c02006-08-31 15:14:32 -0700630 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -0700631 struct hlist_node *entry;
632 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633restart:
David S. Miller8f126e32006-08-24 02:45:07 -0700634 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (!xfrm_state_kern(x) &&
Masahide NAKAMURA57947082006-09-22 15:06:24 -0700636 xfrm_id_proto_match(x->id.proto, proto)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 xfrm_state_hold(x);
638 spin_unlock_bh(&xfrm_state_lock);
639
Joy Latten161a09e2006-11-27 13:11:54 -0600640 err = xfrm_state_delete(x);
Joy Lattenab5f5e82007-09-17 11:51:22 -0700641 xfrm_audit_state_delete(x, err ? 0 : 1,
642 audit_info->loginuid,
Eric Paris25323862008-04-18 10:09:25 -0400643 audit_info->sessionid,
Joy Lattenab5f5e82007-09-17 11:51:22 -0700644 audit_info->secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 xfrm_state_put(x);
646
647 spin_lock_bh(&xfrm_state_lock);
648 goto restart;
649 }
650 }
651 }
Joy Latten4aa2e622007-06-04 19:05:57 -0400652 err = 0;
653
654out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 spin_unlock_bh(&xfrm_state_lock);
656 wake_up(&km_waitq);
Joy Latten4aa2e622007-06-04 19:05:57 -0400657 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659EXPORT_SYMBOL(xfrm_state_flush);
660
Jamal Hadi Salimaf11e312007-05-04 12:55:13 -0700661void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
Jamal Hadi Salim28d89092007-04-26 00:10:29 -0700662{
663 spin_lock_bh(&xfrm_state_lock);
664 si->sadcnt = xfrm_state_num;
665 si->sadhcnt = xfrm_state_hmask;
666 si->sadhmcnt = xfrm_state_hashmax;
667 spin_unlock_bh(&xfrm_state_lock);
668}
669EXPORT_SYMBOL(xfrm_sad_getinfo);
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671static int
672xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
673 struct xfrm_tmpl *tmpl,
674 xfrm_address_t *daddr, xfrm_address_t *saddr,
675 unsigned short family)
676{
677 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
678 if (!afinfo)
679 return -1;
680 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr);
681 xfrm_state_put_afinfo(afinfo);
682 return 0;
683}
684
Al Viroa94cfd12006-09-27 18:47:24 -0700685static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
David S. Milleredcd5822006-08-24 00:42:45 -0700686{
687 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
688 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700689 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700690
David S. Miller8f126e32006-08-24 02:45:07 -0700691 hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
David S. Milleredcd5822006-08-24 00:42:45 -0700692 if (x->props.family != family ||
693 x->id.spi != spi ||
694 x->id.proto != proto)
695 continue;
696
697 switch (family) {
698 case AF_INET:
699 if (x->id.daddr.a4 != daddr->a4)
700 continue;
701 break;
702 case AF_INET6:
703 if (!ipv6_addr_equal((struct in6_addr *)daddr,
704 (struct in6_addr *)
705 x->id.daddr.a6))
706 continue;
707 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700708 }
David S. Milleredcd5822006-08-24 00:42:45 -0700709
710 xfrm_state_hold(x);
711 return x;
712 }
713
714 return NULL;
715}
716
717static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
718{
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700719 unsigned int h = xfrm_src_hash(daddr, saddr, family);
David S. Milleredcd5822006-08-24 00:42:45 -0700720 struct xfrm_state *x;
David S. Miller8f126e32006-08-24 02:45:07 -0700721 struct hlist_node *entry;
David S. Milleredcd5822006-08-24 00:42:45 -0700722
David S. Miller8f126e32006-08-24 02:45:07 -0700723 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
David S. Milleredcd5822006-08-24 00:42:45 -0700724 if (x->props.family != family ||
725 x->id.proto != proto)
726 continue;
727
728 switch (family) {
729 case AF_INET:
730 if (x->id.daddr.a4 != daddr->a4 ||
731 x->props.saddr.a4 != saddr->a4)
732 continue;
733 break;
734 case AF_INET6:
735 if (!ipv6_addr_equal((struct in6_addr *)daddr,
736 (struct in6_addr *)
737 x->id.daddr.a6) ||
738 !ipv6_addr_equal((struct in6_addr *)saddr,
739 (struct in6_addr *)
740 x->props.saddr.a6))
741 continue;
742 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700743 }
David S. Milleredcd5822006-08-24 00:42:45 -0700744
745 xfrm_state_hold(x);
746 return x;
747 }
748
749 return NULL;
750}
751
752static inline struct xfrm_state *
753__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
754{
755 if (use_spi)
756 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
757 x->id.proto, family);
758 else
759 return __xfrm_state_lookup_byaddr(&x->id.daddr,
760 &x->props.saddr,
761 x->id.proto, family);
762}
763
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700764static void xfrm_hash_grow_check(int have_hash_collision)
765{
766 if (have_hash_collision &&
767 (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
768 xfrm_state_num > xfrm_state_hmask)
769 schedule_work(&xfrm_hash_work);
770}
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900773xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 struct flowi *fl, struct xfrm_tmpl *tmpl,
775 struct xfrm_policy *pol, int *err,
776 unsigned short family)
777{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800778 unsigned int h;
David S. Miller8f126e32006-08-24 02:45:07 -0700779 struct hlist_node *entry;
David S. Miller37b08e32008-09-02 20:14:15 -0700780 struct xfrm_state *x, *x0, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 int acquire_in_progress = 0;
782 int error = 0;
783 struct xfrm_state *best = NULL;
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +0900784
David S. Miller37b08e32008-09-02 20:14:15 -0700785 to_put = NULL;
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 spin_lock_bh(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800788 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700789 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (x->props.family == family &&
791 x->props.reqid == tmpl->reqid &&
Masahide NAKAMURAfbd9a5b2006-08-23 18:08:21 -0700792 !(x->props.flags & XFRM_STATE_WILDRECV) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 xfrm_state_addr_check(x, daddr, saddr, family) &&
794 tmpl->mode == x->props.mode &&
795 tmpl->id.proto == x->id.proto &&
796 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
797 /* Resolution logic:
798 1. There is a valid state with matching selector.
799 Done.
800 2. Valid state with inappropriate selector. Skip.
801
802 Entering area of "sysdeps".
803
804 3. If state is not valid, selector is temporary,
805 it selects only session which triggered
806 previous resolution. Key manager will do
807 something to install a state with proper
808 selector.
809 */
810 if (x->km.state == XFRM_STATE_VALID) {
Kazunori MIYAZAWAdf9dcb42008-03-24 14:51:51 -0700811 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700812 !security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 continue;
814 if (!best ||
815 best->km.dying > x->km.dying ||
816 (best->km.dying == x->km.dying &&
817 best->curlft.add_time < x->curlft.add_time))
818 best = x;
819 } else if (x->km.state == XFRM_STATE_ACQ) {
820 acquire_in_progress = 1;
821 } else if (x->km.state == XFRM_STATE_ERROR ||
822 x->km.state == XFRM_STATE_EXPIRED) {
Joakim Koskela48b8d782007-07-26 00:08:42 -0700823 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700824 security_xfrm_state_pol_flow_match(x, pol, fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 error = -ESRCH;
826 }
827 }
828 }
829
830 x = best;
831 if (!x && !error && !acquire_in_progress) {
Patrick McHardy5c5d2812005-04-21 20:12:32 -0700832 if (tmpl->id.spi &&
David S. Milleredcd5822006-08-24 00:42:45 -0700833 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
834 tmpl->id.proto, family)) != NULL) {
David S. Miller37b08e32008-09-02 20:14:15 -0700835 to_put = x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 error = -EEXIST;
837 goto out;
838 }
Alexey Dobriyan673c09b2008-11-25 17:15:16 -0800839 x = xfrm_state_alloc(&init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (x == NULL) {
841 error = -ENOMEM;
842 goto out;
843 }
844 /* Initialize temporary selector matching only
845 * to current session. */
846 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family);
847
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700848 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
849 if (error) {
850 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700851 to_put = x;
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -0700852 x = NULL;
853 goto out;
854 }
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 if (km_query(x, tmpl, pol) == 0) {
857 x->km.state = XFRM_STATE_ACQ;
Herbert Xu12a169e2008-10-01 07:03:24 -0700858 list_add(&x->km.all, &xfrm_state_all);
David S. Miller8f126e32006-08-24 02:45:07 -0700859 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700860 h = xfrm_src_hash(daddr, saddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700861 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (x->id.spi) {
863 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700864 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 }
David S. Miller01e67d02007-05-25 00:41:38 -0700866 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
867 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 add_timer(&x->timer);
Patrick McHardy2fab22f2006-10-24 15:34:00 -0700869 xfrm_state_num++;
870 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 } else {
872 x->km.state = XFRM_STATE_DEAD;
David S. Miller37b08e32008-09-02 20:14:15 -0700873 to_put = x;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 x = NULL;
875 error = -ESRCH;
876 }
877 }
878out:
879 if (x)
880 xfrm_state_hold(x);
881 else
882 *err = acquire_in_progress ? -EAGAIN : error;
883 spin_unlock_bh(&xfrm_state_lock);
David S. Miller37b08e32008-09-02 20:14:15 -0700884 if (to_put)
885 xfrm_state_put(to_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return x;
887}
888
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700889struct xfrm_state *
890xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
891 unsigned short family, u8 mode, u8 proto, u32 reqid)
892{
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800893 unsigned int h;
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700894 struct xfrm_state *rx = NULL, *x = NULL;
895 struct hlist_node *entry;
896
897 spin_lock(&xfrm_state_lock);
Pavel Emelyanov4bda4f22007-12-14 11:38:04 -0800898 h = xfrm_dst_hash(daddr, saddr, reqid, family);
Jamal Hadi Salim628529b2007-07-02 22:41:14 -0700899 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
900 if (x->props.family == family &&
901 x->props.reqid == reqid &&
902 !(x->props.flags & XFRM_STATE_WILDRECV) &&
903 xfrm_state_addr_check(x, daddr, saddr, family) &&
904 mode == x->props.mode &&
905 proto == x->id.proto &&
906 x->km.state == XFRM_STATE_VALID) {
907 rx = x;
908 break;
909 }
910 }
911
912 if (rx)
913 xfrm_state_hold(rx);
914 spin_unlock(&xfrm_state_lock);
915
916
917 return rx;
918}
919EXPORT_SYMBOL(xfrm_stateonly_find);
920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921static void __xfrm_state_insert(struct xfrm_state *x)
922{
David S. Millera624c102006-08-24 03:24:33 -0700923 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
David S. Miller9d4a7062006-08-24 03:18:09 -0700925 x->genid = ++xfrm_state_genid;
926
Herbert Xu12a169e2008-10-01 07:03:24 -0700927 list_add(&x->km.all, &xfrm_state_all);
Timo Teras4c563f72008-02-28 21:31:08 -0800928
David S. Millerc1969f22006-08-24 04:00:03 -0700929 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
930 x->props.reqid, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -0700931 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -0700933 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -0700934 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Masahide NAKAMURA7b4dc3602006-09-27 22:21:52 -0700936 if (x->id.spi) {
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700937 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
938 x->props.family);
939
David S. Miller8f126e32006-08-24 02:45:07 -0700940 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700941 }
942
David S. Millera47f0ce2006-08-24 03:54:22 -0700943 mod_timer(&x->timer, jiffies + HZ);
944 if (x->replay_maxage)
945 mod_timer(&x->rtimer, jiffies + x->replay_maxage);
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -0800946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 wake_up(&km_waitq);
David S. Millerf034b5d2006-08-24 03:08:07 -0700948
949 xfrm_state_num++;
950
David S. Miller918049f2006-10-12 22:03:24 -0700951 xfrm_hash_grow_check(x->bydst.next != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
David S. Millerc7f5ea32006-08-24 03:29:04 -0700954/* xfrm_state_lock is held */
955static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
956{
957 unsigned short family = xnew->props.family;
958 u32 reqid = xnew->props.reqid;
959 struct xfrm_state *x;
960 struct hlist_node *entry;
961 unsigned int h;
962
David S. Millerc1969f22006-08-24 04:00:03 -0700963 h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700964 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
965 if (x->props.family == family &&
966 x->props.reqid == reqid &&
David S. Millerc1969f22006-08-24 04:00:03 -0700967 !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
968 !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
David S. Millerc7f5ea32006-08-24 03:29:04 -0700969 x->genid = xfrm_state_genid;
970 }
971}
972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973void xfrm_state_insert(struct xfrm_state *x)
974{
975 spin_lock_bh(&xfrm_state_lock);
David S. Millerc7f5ea32006-08-24 03:29:04 -0700976 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 __xfrm_state_insert(x);
978 spin_unlock_bh(&xfrm_state_lock);
979}
980EXPORT_SYMBOL(xfrm_state_insert);
981
David S. Miller27708342006-08-24 00:13:10 -0700982/* xfrm_state_lock is held */
983static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
984{
David S. Millerc1969f22006-08-24 04:00:03 -0700985 unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
David S. Miller8f126e32006-08-24 02:45:07 -0700986 struct hlist_node *entry;
David S. Miller27708342006-08-24 00:13:10 -0700987 struct xfrm_state *x;
988
David S. Miller8f126e32006-08-24 02:45:07 -0700989 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
David S. Miller27708342006-08-24 00:13:10 -0700990 if (x->props.reqid != reqid ||
991 x->props.mode != mode ||
992 x->props.family != family ||
993 x->km.state != XFRM_STATE_ACQ ||
Joy Latten75e252d2007-03-12 17:14:07 -0700994 x->id.spi != 0 ||
995 x->id.proto != proto)
David S. Miller27708342006-08-24 00:13:10 -0700996 continue;
997
998 switch (family) {
999 case AF_INET:
1000 if (x->id.daddr.a4 != daddr->a4 ||
1001 x->props.saddr.a4 != saddr->a4)
1002 continue;
1003 break;
1004 case AF_INET6:
1005 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
1006 (struct in6_addr *)daddr) ||
1007 !ipv6_addr_equal((struct in6_addr *)
1008 x->props.saddr.a6,
1009 (struct in6_addr *)saddr))
1010 continue;
1011 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001012 }
David S. Miller27708342006-08-24 00:13:10 -07001013
1014 xfrm_state_hold(x);
1015 return x;
1016 }
1017
1018 if (!create)
1019 return NULL;
1020
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001021 x = xfrm_state_alloc(&init_net);
David S. Miller27708342006-08-24 00:13:10 -07001022 if (likely(x)) {
1023 switch (family) {
1024 case AF_INET:
1025 x->sel.daddr.a4 = daddr->a4;
1026 x->sel.saddr.a4 = saddr->a4;
1027 x->sel.prefixlen_d = 32;
1028 x->sel.prefixlen_s = 32;
1029 x->props.saddr.a4 = saddr->a4;
1030 x->id.daddr.a4 = daddr->a4;
1031 break;
1032
1033 case AF_INET6:
1034 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
1035 (struct in6_addr *)daddr);
1036 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
1037 (struct in6_addr *)saddr);
1038 x->sel.prefixlen_d = 128;
1039 x->sel.prefixlen_s = 128;
1040 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
1041 (struct in6_addr *)saddr);
1042 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
1043 (struct in6_addr *)daddr);
1044 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001045 }
David S. Miller27708342006-08-24 00:13:10 -07001046
1047 x->km.state = XFRM_STATE_ACQ;
1048 x->id.proto = proto;
1049 x->props.family = family;
1050 x->props.mode = mode;
1051 x->props.reqid = reqid;
David S. Miller01e67d02007-05-25 00:41:38 -07001052 x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
David S. Miller27708342006-08-24 00:13:10 -07001053 xfrm_state_hold(x);
David S. Miller01e67d02007-05-25 00:41:38 -07001054 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
David S. Miller27708342006-08-24 00:13:10 -07001055 add_timer(&x->timer);
Herbert Xu12a169e2008-10-01 07:03:24 -07001056 list_add(&x->km.all, &xfrm_state_all);
David S. Miller8f126e32006-08-24 02:45:07 -07001057 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
Masahide NAKAMURA667bbcb2006-10-03 15:56:09 -07001058 h = xfrm_src_hash(daddr, saddr, family);
David S. Miller8f126e32006-08-24 02:45:07 -07001059 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
David S. Miller918049f2006-10-12 22:03:24 -07001060
1061 xfrm_state_num++;
1062
1063 xfrm_hash_grow_check(x->bydst.next != NULL);
David S. Miller27708342006-08-24 00:13:10 -07001064 }
1065
1066 return x;
1067}
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1070
1071int xfrm_state_add(struct xfrm_state *x)
1072{
David S. Miller37b08e32008-09-02 20:14:15 -07001073 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 int family;
1075 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001076 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 family = x->props.family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
David S. Miller37b08e32008-09-02 20:14:15 -07001080 to_put = NULL;
1081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 spin_lock_bh(&xfrm_state_lock);
1083
David S. Milleredcd5822006-08-24 00:42:45 -07001084 x1 = __xfrm_state_locate(x, use_spi, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (x1) {
David S. Miller37b08e32008-09-02 20:14:15 -07001086 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 x1 = NULL;
1088 err = -EEXIST;
1089 goto out;
1090 }
1091
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001092 if (use_spi && x->km.seq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 x1 = __xfrm_find_acq_byseq(x->km.seq);
Joy Latten75e252d2007-03-12 17:14:07 -07001094 if (x1 && ((x1->id.proto != x->id.proto) ||
1095 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
David S. Miller37b08e32008-09-02 20:14:15 -07001096 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 x1 = NULL;
1098 }
1099 }
1100
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001101 if (use_spi && !x1)
David S. Miller27708342006-08-24 00:13:10 -07001102 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
1103 x->id.proto,
1104 &x->id.daddr, &x->props.saddr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
David S. Millerc7f5ea32006-08-24 03:29:04 -07001106 __xfrm_state_bump_genids(x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 __xfrm_state_insert(x);
1108 err = 0;
1109
1110out:
1111 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 if (x1) {
1114 xfrm_state_delete(x1);
1115 xfrm_state_put(x1);
1116 }
1117
David S. Miller37b08e32008-09-02 20:14:15 -07001118 if (to_put)
1119 xfrm_state_put(to_put);
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 return err;
1122}
1123EXPORT_SYMBOL(xfrm_state_add);
1124
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001125#ifdef CONFIG_XFRM_MIGRATE
Eric Dumazet66663512008-01-08 01:35:52 -08001126static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001127{
1128 int err = -ENOMEM;
Alexey Dobriyan673c09b2008-11-25 17:15:16 -08001129 struct xfrm_state *x = xfrm_state_alloc(&init_net);
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001130 if (!x)
1131 goto error;
1132
1133 memcpy(&x->id, &orig->id, sizeof(x->id));
1134 memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1135 memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1136 x->props.mode = orig->props.mode;
1137 x->props.replay_window = orig->props.replay_window;
1138 x->props.reqid = orig->props.reqid;
1139 x->props.family = orig->props.family;
1140 x->props.saddr = orig->props.saddr;
1141
1142 if (orig->aalg) {
1143 x->aalg = xfrm_algo_clone(orig->aalg);
1144 if (!x->aalg)
1145 goto error;
1146 }
1147 x->props.aalgo = orig->props.aalgo;
1148
1149 if (orig->ealg) {
1150 x->ealg = xfrm_algo_clone(orig->ealg);
1151 if (!x->ealg)
1152 goto error;
1153 }
1154 x->props.ealgo = orig->props.ealgo;
1155
1156 if (orig->calg) {
1157 x->calg = xfrm_algo_clone(orig->calg);
1158 if (!x->calg)
1159 goto error;
1160 }
1161 x->props.calgo = orig->props.calgo;
1162
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001163 if (orig->encap) {
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001164 x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
1165 if (!x->encap)
1166 goto error;
1167 }
1168
1169 if (orig->coaddr) {
1170 x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1171 GFP_KERNEL);
1172 if (!x->coaddr)
1173 goto error;
1174 }
1175
1176 err = xfrm_init_state(x);
1177 if (err)
1178 goto error;
1179
1180 x->props.flags = orig->props.flags;
1181
1182 x->curlft.add_time = orig->curlft.add_time;
1183 x->km.state = orig->km.state;
1184 x->km.seq = orig->km.seq;
1185
1186 return x;
1187
1188 error:
1189 if (errp)
1190 *errp = err;
1191 if (x) {
1192 kfree(x->aalg);
1193 kfree(x->ealg);
1194 kfree(x->calg);
1195 kfree(x->encap);
1196 kfree(x->coaddr);
1197 }
1198 kfree(x);
1199 return NULL;
1200}
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001201
1202/* xfrm_state_lock is held */
1203struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
1204{
1205 unsigned int h;
1206 struct xfrm_state *x;
1207 struct hlist_node *entry;
1208
1209 if (m->reqid) {
1210 h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
1211 m->reqid, m->old_family);
1212 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
1213 if (x->props.mode != m->mode ||
1214 x->id.proto != m->proto)
1215 continue;
1216 if (m->reqid && x->props.reqid != m->reqid)
1217 continue;
1218 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1219 m->old_family) ||
1220 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1221 m->old_family))
1222 continue;
1223 xfrm_state_hold(x);
1224 return x;
1225 }
1226 } else {
1227 h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
1228 m->old_family);
1229 hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
1230 if (x->props.mode != m->mode ||
1231 x->id.proto != m->proto)
1232 continue;
1233 if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
1234 m->old_family) ||
1235 xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
1236 m->old_family))
1237 continue;
1238 xfrm_state_hold(x);
1239 return x;
1240 }
1241 }
1242
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001243 return NULL;
Shinta Sugimoto80c9aba2007-02-08 13:11:42 -08001244}
1245EXPORT_SYMBOL(xfrm_migrate_state_find);
1246
1247struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
1248 struct xfrm_migrate *m)
1249{
1250 struct xfrm_state *xc;
1251 int err;
1252
1253 xc = xfrm_state_clone(x, &err);
1254 if (!xc)
1255 return NULL;
1256
1257 memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1258 memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1259
1260 /* add state */
1261 if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
1262 /* a care is needed when the destination address of the
1263 state is to be updated as it is a part of triplet */
1264 xfrm_state_insert(xc);
1265 } else {
1266 if ((err = xfrm_state_add(xc)) < 0)
1267 goto error;
1268 }
1269
1270 return xc;
1271error:
1272 kfree(xc);
1273 return NULL;
1274}
1275EXPORT_SYMBOL(xfrm_state_migrate);
1276#endif
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278int xfrm_state_update(struct xfrm_state *x)
1279{
David S. Miller37b08e32008-09-02 20:14:15 -07001280 struct xfrm_state *x1, *to_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 int err;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001282 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
David S. Miller37b08e32008-09-02 20:14:15 -07001284 to_put = NULL;
1285
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001287 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289 err = -ESRCH;
1290 if (!x1)
1291 goto out;
1292
1293 if (xfrm_state_kern(x1)) {
David S. Miller37b08e32008-09-02 20:14:15 -07001294 to_put = x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 err = -EEXIST;
1296 goto out;
1297 }
1298
1299 if (x1->km.state == XFRM_STATE_ACQ) {
1300 __xfrm_state_insert(x);
1301 x = NULL;
1302 }
1303 err = 0;
1304
1305out:
1306 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
David S. Miller37b08e32008-09-02 20:14:15 -07001308 if (to_put)
1309 xfrm_state_put(to_put);
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (err)
1312 return err;
1313
1314 if (!x) {
1315 xfrm_state_delete(x1);
1316 xfrm_state_put(x1);
1317 return 0;
1318 }
1319
1320 err = -EINVAL;
1321 spin_lock_bh(&x1->lock);
1322 if (likely(x1->km.state == XFRM_STATE_VALID)) {
1323 if (x->encap && x1->encap)
1324 memcpy(x1->encap, x->encap, sizeof(*x1->encap));
Noriaki TAKAMIYA060f02a2006-08-23 18:18:55 -07001325 if (x->coaddr && x1->coaddr) {
1326 memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1327 }
1328 if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1329 memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1331 x1->km.dying = 0;
1332
David S. Millera47f0ce2006-08-24 03:54:22 -07001333 mod_timer(&x1->timer, jiffies + HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (x1->curlft.use_time)
1335 xfrm_state_check_expire(x1);
1336
1337 err = 0;
1338 }
1339 spin_unlock_bh(&x1->lock);
1340
1341 xfrm_state_put(x1);
1342
1343 return err;
1344}
1345EXPORT_SYMBOL(xfrm_state_update);
1346
1347int xfrm_state_check_expire(struct xfrm_state *x)
1348{
1349 if (!x->curlft.use_time)
James Morris9d729f72007-03-04 16:12:44 -08001350 x->curlft.use_time = get_seconds();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
1352 if (x->km.state != XFRM_STATE_VALID)
1353 return -EINVAL;
1354
1355 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1356 x->curlft.packets >= x->lft.hard_packet_limit) {
Herbert Xu4666faa2005-06-18 22:43:22 -07001357 x->km.state = XFRM_STATE_EXPIRED;
David S. Millera47f0ce2006-08-24 03:54:22 -07001358 mod_timer(&x->timer, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 return -EINVAL;
1360 }
1361
1362 if (!x->km.dying &&
1363 (x->curlft.bytes >= x->lft.soft_byte_limit ||
Herbert Xu4666faa2005-06-18 22:43:22 -07001364 x->curlft.packets >= x->lft.soft_packet_limit)) {
1365 x->km.dying = 1;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001366 km_state_expired(x, 0, 0);
Herbert Xu4666faa2005-06-18 22:43:22 -07001367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 return 0;
1369}
1370EXPORT_SYMBOL(xfrm_state_check_expire);
1371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372struct xfrm_state *
Al Viroa94cfd12006-09-27 18:47:24 -07001373xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 unsigned short family)
1375{
1376 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001379 x = __xfrm_state_lookup(daddr, spi, proto, family);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 spin_unlock_bh(&xfrm_state_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 return x;
1382}
1383EXPORT_SYMBOL(xfrm_state_lookup);
1384
1385struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001386xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
1387 u8 proto, unsigned short family)
1388{
1389 struct xfrm_state *x;
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001390
1391 spin_lock_bh(&xfrm_state_lock);
David S. Milleredcd5822006-08-24 00:42:45 -07001392 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001393 spin_unlock_bh(&xfrm_state_lock);
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -07001394 return x;
1395}
1396EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1397
1398struct xfrm_state *
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09001399xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1400 xfrm_address_t *daddr, xfrm_address_t *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 int create, unsigned short family)
1402{
1403 struct xfrm_state *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 spin_lock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001406 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 spin_unlock_bh(&xfrm_state_lock);
David S. Miller27708342006-08-24 00:13:10 -07001408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return x;
1410}
1411EXPORT_SYMBOL(xfrm_find_acq);
1412
Masahide NAKAMURA41a49cc2006-08-23 22:48:31 -07001413#ifdef CONFIG_XFRM_SUB_POLICY
1414int
1415xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1416 unsigned short family)
1417{
1418 int err = 0;
1419 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1420 if (!afinfo)
1421 return -EAFNOSUPPORT;
1422
1423 spin_lock_bh(&xfrm_state_lock);
1424 if (afinfo->tmpl_sort)
1425 err = afinfo->tmpl_sort(dst, src, n);
1426 spin_unlock_bh(&xfrm_state_lock);
1427 xfrm_state_put_afinfo(afinfo);
1428 return err;
1429}
1430EXPORT_SYMBOL(xfrm_tmpl_sort);
1431
1432int
1433xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1434 unsigned short family)
1435{
1436 int err = 0;
1437 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1438 if (!afinfo)
1439 return -EAFNOSUPPORT;
1440
1441 spin_lock_bh(&xfrm_state_lock);
1442 if (afinfo->state_sort)
1443 err = afinfo->state_sort(dst, src, n);
1444 spin_unlock_bh(&xfrm_state_lock);
1445 xfrm_state_put_afinfo(afinfo);
1446 return err;
1447}
1448EXPORT_SYMBOL(xfrm_state_sort);
1449#endif
1450
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451/* Silly enough, but I'm lazy to build resolution list */
1452
1453static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
1454{
1455 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
David S. Millerf034b5d2006-08-24 03:08:07 -07001457 for (i = 0; i <= xfrm_state_hmask; i++) {
David S. Miller8f126e32006-08-24 02:45:07 -07001458 struct hlist_node *entry;
1459 struct xfrm_state *x;
1460
1461 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
1462 if (x->km.seq == seq &&
1463 x->km.state == XFRM_STATE_ACQ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 xfrm_state_hold(x);
1465 return x;
1466 }
1467 }
1468 }
1469 return NULL;
1470}
1471
1472struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
1473{
1474 struct xfrm_state *x;
1475
1476 spin_lock_bh(&xfrm_state_lock);
1477 x = __xfrm_find_acq_byseq(seq);
1478 spin_unlock_bh(&xfrm_state_lock);
1479 return x;
1480}
1481EXPORT_SYMBOL(xfrm_find_acq_byseq);
1482
1483u32 xfrm_get_acqseq(void)
1484{
1485 u32 res;
1486 static u32 acqseq;
1487 static DEFINE_SPINLOCK(acqseq_lock);
1488
1489 spin_lock_bh(&acqseq_lock);
1490 res = (++acqseq ? : ++acqseq);
1491 spin_unlock_bh(&acqseq_lock);
1492 return res;
1493}
1494EXPORT_SYMBOL(xfrm_get_acqseq);
1495
Herbert Xu658b2192007-10-09 13:29:52 -07001496int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
David S. Millerf034b5d2006-08-24 03:08:07 -07001498 unsigned int h;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 struct xfrm_state *x0;
Herbert Xu658b2192007-10-09 13:29:52 -07001500 int err = -ENOENT;
1501 __be32 minspi = htonl(low);
1502 __be32 maxspi = htonl(high);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
Herbert Xu658b2192007-10-09 13:29:52 -07001504 spin_lock_bh(&x->lock);
1505 if (x->km.state == XFRM_STATE_DEAD)
1506 goto unlock;
1507
1508 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 if (x->id.spi)
Herbert Xu658b2192007-10-09 13:29:52 -07001510 goto unlock;
1511
1512 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 if (minspi == maxspi) {
1515 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1516 if (x0) {
1517 xfrm_state_put(x0);
Herbert Xu658b2192007-10-09 13:29:52 -07001518 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 }
1520 x->id.spi = minspi;
1521 } else {
1522 u32 spi = 0;
Al Viro26977b42006-09-27 18:47:05 -07001523 for (h=0; h<high-low+1; h++) {
1524 spi = low + net_random()%(high-low+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
1526 if (x0 == NULL) {
1527 x->id.spi = htonl(spi);
1528 break;
1529 }
1530 xfrm_state_put(x0);
1531 }
1532 }
1533 if (x->id.spi) {
1534 spin_lock_bh(&xfrm_state_lock);
1535 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
David S. Miller8f126e32006-08-24 02:45:07 -07001536 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 spin_unlock_bh(&xfrm_state_lock);
Herbert Xu658b2192007-10-09 13:29:52 -07001538
1539 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 }
Herbert Xu658b2192007-10-09 13:29:52 -07001541
1542unlock:
1543 spin_unlock_bh(&x->lock);
1544
1545 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546}
1547EXPORT_SYMBOL(xfrm_alloc_spi);
1548
Timo Teras4c563f72008-02-28 21:31:08 -08001549int xfrm_state_walk(struct xfrm_state_walk *walk,
1550 int (*func)(struct xfrm_state *, int, void*),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 void *data)
1552{
Herbert Xu12a169e2008-10-01 07:03:24 -07001553 struct xfrm_state *state;
1554 struct xfrm_state_walk *x;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 int err = 0;
1556
Herbert Xu12a169e2008-10-01 07:03:24 -07001557 if (walk->seq != 0 && list_empty(&walk->all))
Timo Teras4c563f72008-02-28 21:31:08 -08001558 return 0;
1559
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 spin_lock_bh(&xfrm_state_lock);
Herbert Xu12a169e2008-10-01 07:03:24 -07001561 if (list_empty(&walk->all))
1562 x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all);
1563 else
1564 x = list_entry(&walk->all, struct xfrm_state_walk, all);
Timo Teras4c563f72008-02-28 21:31:08 -08001565 list_for_each_entry_from(x, &xfrm_state_all, all) {
Herbert Xu12a169e2008-10-01 07:03:24 -07001566 if (x->state == XFRM_STATE_DEAD)
Timo Teras4c563f72008-02-28 21:31:08 -08001567 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001568 state = container_of(x, struct xfrm_state, km);
1569 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
Timo Teras4c563f72008-02-28 21:31:08 -08001570 continue;
Herbert Xu12a169e2008-10-01 07:03:24 -07001571 err = func(state, walk->seq, data);
1572 if (err) {
1573 list_move_tail(&walk->all, &x->all);
1574 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001576 walk->seq++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001578 if (walk->seq == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 err = -ENOENT;
1580 goto out;
1581 }
Herbert Xu12a169e2008-10-01 07:03:24 -07001582 list_del_init(&walk->all);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583out:
1584 spin_unlock_bh(&xfrm_state_lock);
1585 return err;
1586}
1587EXPORT_SYMBOL(xfrm_state_walk);
1588
Herbert Xu5c182452008-09-22 19:48:19 -07001589void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1590{
Herbert Xu12a169e2008-10-01 07:03:24 -07001591 INIT_LIST_HEAD(&walk->all);
Herbert Xu5c182452008-09-22 19:48:19 -07001592 walk->proto = proto;
Herbert Xu12a169e2008-10-01 07:03:24 -07001593 walk->state = XFRM_STATE_DEAD;
1594 walk->seq = 0;
Herbert Xu5c182452008-09-22 19:48:19 -07001595}
1596EXPORT_SYMBOL(xfrm_state_walk_init);
1597
Herbert Xuabb81c42008-09-09 19:58:29 -07001598void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1599{
Herbert Xu12a169e2008-10-01 07:03:24 -07001600 if (list_empty(&walk->all))
Herbert Xu5c182452008-09-22 19:48:19 -07001601 return;
Herbert Xu5c182452008-09-22 19:48:19 -07001602
Herbert Xu12a169e2008-10-01 07:03:24 -07001603 spin_lock_bh(&xfrm_state_lock);
1604 list_del(&walk->all);
1605 spin_lock_bh(&xfrm_state_lock);
Herbert Xuabb81c42008-09-09 19:58:29 -07001606}
1607EXPORT_SYMBOL(xfrm_state_walk_done);
1608
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001609
1610void xfrm_replay_notify(struct xfrm_state *x, int event)
1611{
1612 struct km_event c;
1613 /* we send notify messages in case
1614 * 1. we updated on of the sequence numbers, and the seqno difference
1615 * is at least x->replay_maxdiff, in this case we also update the
1616 * timeout of our timer function
1617 * 2. if x->replay_maxage has elapsed since last update,
1618 * and there were changes
1619 *
1620 * The state structure must be locked!
1621 */
1622
1623 switch (event) {
1624 case XFRM_REPLAY_UPDATE:
1625 if (x->replay_maxdiff &&
1626 (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001627 (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
1628 if (x->xflags & XFRM_TIME_DEFER)
1629 event = XFRM_REPLAY_TIMEOUT;
1630 else
1631 return;
1632 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001633
1634 break;
1635
1636 case XFRM_REPLAY_TIMEOUT:
1637 if ((x->replay.seq == x->preplay.seq) &&
1638 (x->replay.bitmap == x->preplay.bitmap) &&
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001639 (x->replay.oseq == x->preplay.oseq)) {
1640 x->xflags |= XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001641 return;
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001642 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001643
1644 break;
1645 }
1646
1647 memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
1648 c.event = XFRM_MSG_NEWAE;
1649 c.data.aevent = event;
1650 km_state_notify(x, &c);
1651
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001652 if (x->replay_maxage &&
David S. Millera47f0ce2006-08-24 03:54:22 -07001653 !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001654 x->xflags &= ~XFRM_TIME_DEFER;
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001655}
1656
1657static void xfrm_replay_timer_handler(unsigned long data)
1658{
1659 struct xfrm_state *x = (struct xfrm_state*)data;
1660
1661 spin_lock(&x->lock);
1662
Jamal Hadi Salim27170962006-04-14 15:03:05 -07001663 if (x->km.state == XFRM_STATE_VALID) {
1664 if (xfrm_aevent_is_on())
1665 xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
1666 else
1667 x->xflags |= XFRM_TIME_DEFER;
1668 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001669
1670 spin_unlock(&x->lock);
1671}
1672
Paul Mooreafeb14b2007-12-21 14:58:11 -08001673int xfrm_replay_check(struct xfrm_state *x,
1674 struct sk_buff *skb, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675{
1676 u32 diff;
Al Viroa252cc22006-09-27 18:48:18 -07001677 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 if (unlikely(seq == 0))
Paul Mooreafeb14b2007-12-21 14:58:11 -08001680 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682 if (likely(seq > x->replay.seq))
1683 return 0;
1684
1685 diff = x->replay.seq - seq;
Herbert Xu4c4d51a72007-04-05 00:07:39 -07001686 if (diff >= min_t(unsigned int, x->props.replay_window,
1687 sizeof(x->replay.bitmap) * 8)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 x->stats.replay_window++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001689 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691
1692 if (x->replay.bitmap & (1U << diff)) {
1693 x->stats.replay++;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001694 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 }
1696 return 0;
Paul Mooreafeb14b2007-12-21 14:58:11 -08001697
1698err:
1699 xfrm_audit_state_replay(x, skb, net_seq);
1700 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Al Viro61f46272006-09-27 18:48:33 -07001703void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704{
1705 u32 diff;
Al Viro61f46272006-09-27 18:48:33 -07001706 u32 seq = ntohl(net_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 if (seq > x->replay.seq) {
1709 diff = seq - x->replay.seq;
1710 if (diff < x->props.replay_window)
1711 x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
1712 else
1713 x->replay.bitmap = 1;
1714 x->replay.seq = seq;
1715 } else {
1716 diff = x->replay.seq - seq;
1717 x->replay.bitmap |= (1U << diff);
1718 }
Jamal Hadi Salimf8cd5482006-03-20 19:15:11 -08001719
1720 if (xfrm_aevent_is_on())
1721 xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
Denis Chengdf018122007-12-07 00:51:11 -08001724static LIST_HEAD(xfrm_km_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725static DEFINE_RWLOCK(xfrm_km_lock);
1726
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001727void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
1729 struct xfrm_mgr *km;
1730
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001731 read_lock(&xfrm_km_lock);
1732 list_for_each_entry(km, &xfrm_km_list, list)
1733 if (km->notify_policy)
1734 km->notify_policy(xp, dir, c);
1735 read_unlock(&xfrm_km_lock);
1736}
1737
1738void km_state_notify(struct xfrm_state *x, struct km_event *c)
1739{
1740 struct xfrm_mgr *km;
1741 read_lock(&xfrm_km_lock);
1742 list_for_each_entry(km, &xfrm_km_list, list)
1743 if (km->notify)
1744 km->notify(x, c);
1745 read_unlock(&xfrm_km_lock);
1746}
1747
1748EXPORT_SYMBOL(km_policy_notify);
1749EXPORT_SYMBOL(km_state_notify);
1750
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001751void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001752{
1753 struct km_event c;
1754
Herbert Xubf088672005-06-18 22:44:00 -07001755 c.data.hard = hard;
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001756 c.pid = pid;
Herbert Xuf60f6b82005-06-18 22:44:37 -07001757 c.event = XFRM_MSG_EXPIRE;
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001758 km_state_notify(x, &c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 if (hard)
1761 wake_up(&km_waitq);
1762}
1763
Jamal Hadi Salim53bc6b42006-03-20 19:17:03 -08001764EXPORT_SYMBOL(km_state_expired);
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001765/*
1766 * We send to all registered managers regardless of failure
1767 * We are happy with one success
1768*/
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001769int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001771 int err = -EINVAL, acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 struct xfrm_mgr *km;
1773
1774 read_lock(&xfrm_km_lock);
1775 list_for_each_entry(km, &xfrm_km_list, list) {
Jamal Hadi Salim26b15da2005-06-18 22:42:13 -07001776 acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
1777 if (!acqret)
1778 err = acqret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 }
1780 read_unlock(&xfrm_km_lock);
1781 return err;
1782}
Jamal Hadi Salim980ebd22006-03-20 19:16:40 -08001783EXPORT_SYMBOL(km_query);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Al Viro5d36b182006-11-08 00:24:06 -08001785int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786{
1787 int err = -EINVAL;
1788 struct xfrm_mgr *km;
1789
1790 read_lock(&xfrm_km_lock);
1791 list_for_each_entry(km, &xfrm_km_list, list) {
1792 if (km->new_mapping)
1793 err = km->new_mapping(x, ipaddr, sport);
1794 if (!err)
1795 break;
1796 }
1797 read_unlock(&xfrm_km_lock);
1798 return err;
1799}
1800EXPORT_SYMBOL(km_new_mapping);
1801
Jamal Hadi Salim6c5c8ca2006-03-20 19:17:25 -08001802void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803{
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)
1812 wake_up(&km_waitq);
1813}
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
David S. Millerf034b5d2006-08-24 03:08:07 -07002088 sz = sizeof(struct hlist_head) * 8;
2089
David S. Miller44e36b42006-08-24 04:50:50 -07002090 xfrm_state_bydst = xfrm_hash_alloc(sz);
2091 xfrm_state_bysrc = xfrm_hash_alloc(sz);
2092 xfrm_state_byspi = xfrm_hash_alloc(sz);
David S. Millerf034b5d2006-08-24 03:08:07 -07002093 if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
2094 panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
2095 xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
2096
David Howellsc4028952006-11-22 14:57:56 +00002097 INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
Alexey Dobriyand62ddc22008-11-25 17:14:31 -08002098 return 0;
2099}
2100
2101void xfrm_state_fini(struct net *net)
2102{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103}
2104
Joy Lattenab5f5e82007-09-17 11:51:22 -07002105#ifdef CONFIG_AUDITSYSCALL
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002106static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2107 struct audit_buffer *audit_buf)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002108{
Paul Moore68277ac2007-12-20 20:49:33 -08002109 struct xfrm_sec_ctx *ctx = x->security;
2110 u32 spi = ntohl(x->id.spi);
2111
2112 if (ctx)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002113 audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
Paul Moore68277ac2007-12-20 20:49:33 -08002114 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002115
2116 switch(x->props.family) {
2117 case AF_INET:
Harvey Harrison21454aa2008-10-31 00:54:56 -07002118 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2119 &x->props.saddr.a4, &x->id.daddr.a4);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002120 break;
2121 case AF_INET6:
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002122 audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002123 x->props.saddr.a6, x->id.daddr.a6);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002124 break;
2125 }
Paul Moore68277ac2007-12-20 20:49:33 -08002126
2127 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002128}
2129
Ilpo Järvinencf35f432008-01-05 23:13:20 -08002130static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2131 struct audit_buffer *audit_buf)
Paul Mooreafeb14b2007-12-21 14:58:11 -08002132{
2133 struct iphdr *iph4;
2134 struct ipv6hdr *iph6;
2135
2136 switch (family) {
2137 case AF_INET:
2138 iph4 = ip_hdr(skb);
Harvey Harrison21454aa2008-10-31 00:54:56 -07002139 audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2140 &iph4->saddr, &iph4->daddr);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002141 break;
2142 case AF_INET6:
2143 iph6 = ipv6_hdr(skb);
2144 audit_log_format(audit_buf,
Harvey Harrison5b095d9892008-10-29 12:52:50 -07002145 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
Harvey Harrisonfdb46ee2008-10-28 16:10:17 -07002146 &iph6->saddr,&iph6->daddr,
Paul Mooreafeb14b2007-12-21 14:58:11 -08002147 iph6->flow_lbl[0] & 0x0f,
2148 iph6->flow_lbl[1],
2149 iph6->flow_lbl[2]);
2150 break;
2151 }
2152}
2153
Paul Moore68277ac2007-12-20 20:49:33 -08002154void xfrm_audit_state_add(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002155 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002156{
2157 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002158
Paul Mooreafeb14b2007-12-21 14:58:11 -08002159 audit_buf = xfrm_audit_start("SAD-add");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002160 if (audit_buf == NULL)
2161 return;
Eric Paris25323862008-04-18 10:09:25 -04002162 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002163 xfrm_audit_helper_sainfo(x, audit_buf);
2164 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002165 audit_log_end(audit_buf);
2166}
2167EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2168
Paul Moore68277ac2007-12-20 20:49:33 -08002169void xfrm_audit_state_delete(struct xfrm_state *x, int result,
Eric Paris25323862008-04-18 10:09:25 -04002170 uid_t auid, u32 sessionid, u32 secid)
Joy Lattenab5f5e82007-09-17 11:51:22 -07002171{
2172 struct audit_buffer *audit_buf;
Joy Lattenab5f5e82007-09-17 11:51:22 -07002173
Paul Mooreafeb14b2007-12-21 14:58:11 -08002174 audit_buf = xfrm_audit_start("SAD-delete");
Joy Lattenab5f5e82007-09-17 11:51:22 -07002175 if (audit_buf == NULL)
2176 return;
Eric Paris25323862008-04-18 10:09:25 -04002177 xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002178 xfrm_audit_helper_sainfo(x, audit_buf);
2179 audit_log_format(audit_buf, " res=%u", result);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002180 audit_log_end(audit_buf);
2181}
2182EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
Paul Mooreafeb14b2007-12-21 14:58:11 -08002183
2184void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2185 struct sk_buff *skb)
2186{
2187 struct audit_buffer *audit_buf;
2188 u32 spi;
2189
2190 audit_buf = xfrm_audit_start("SA-replay-overflow");
2191 if (audit_buf == NULL)
2192 return;
2193 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2194 /* don't record the sequence number because it's inherent in this kind
2195 * of audit message */
2196 spi = ntohl(x->id.spi);
2197 audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2198 audit_log_end(audit_buf);
2199}
2200EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2201
2202static void xfrm_audit_state_replay(struct xfrm_state *x,
2203 struct sk_buff *skb, __be32 net_seq)
2204{
2205 struct audit_buffer *audit_buf;
2206 u32 spi;
2207
2208 audit_buf = xfrm_audit_start("SA-replayed-pkt");
2209 if (audit_buf == NULL)
2210 return;
2211 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2212 spi = ntohl(x->id.spi);
2213 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2214 spi, spi, ntohl(net_seq));
2215 audit_log_end(audit_buf);
2216}
2217
2218void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2219{
2220 struct audit_buffer *audit_buf;
2221
2222 audit_buf = xfrm_audit_start("SA-notfound");
2223 if (audit_buf == NULL)
2224 return;
2225 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2226 audit_log_end(audit_buf);
2227}
2228EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2229
2230void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2231 __be32 net_spi, __be32 net_seq)
2232{
2233 struct audit_buffer *audit_buf;
2234 u32 spi;
2235
2236 audit_buf = xfrm_audit_start("SA-notfound");
2237 if (audit_buf == NULL)
2238 return;
2239 xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2240 spi = ntohl(net_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}
2245EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2246
2247void xfrm_audit_state_icvfail(struct xfrm_state *x,
2248 struct sk_buff *skb, u8 proto)
2249{
2250 struct audit_buffer *audit_buf;
2251 __be32 net_spi;
2252 __be32 net_seq;
2253
2254 audit_buf = xfrm_audit_start("SA-icv-failure");
2255 if (audit_buf == NULL)
2256 return;
2257 xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2258 if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2259 u32 spi = ntohl(net_spi);
2260 audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2261 spi, spi, ntohl(net_seq));
2262 }
2263 audit_log_end(audit_buf);
2264}
2265EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
Joy Lattenab5f5e82007-09-17 11:51:22 -07002266#endif /* CONFIG_AUDITSYSCALL */